Sommaire

BONJOUR
Musique "Invention BWV784" J.S. BACH 1685-1750

Tutoriel et Help

TCC Tiny Compiler C

Nous veillons aux respects des droits d'auteur : si par erreur un contenu protégé est disponible sans indication sur ce site, merci de contacter l'administrateur, il sera retiré ou mis à jour dans les plus brefs délais.


TCC : Tiny C Compiler

Tiny C Compiler

News

[Note: I am no longer working on TCC. Check the mailing list to get up to date information.]

(Feb 15, 2013) TCC version 0.9.26 is out thanks to Thomas Preud'homme (Changelog). Summary of the changes:

  • Support for C99 VLA
  • Generation of make dependencies (-MD/-MF)
  • Support improved for various architectures (x86-64, arm, OSX, WinCE, kFreeBSD, Hurd)
  • A bunch of bug fixes

(May 20, 2009) TCC version 0.9.25 is out thanks to Grischka (Changelog). TCC version 0.9.25 is the first that supports the x86-64 target. Thanks to Shinichiro Hamaji for this.

(Apr 1, 2008) TCC version 0.9.24 is out thanks to Grischka (Changelog). TCC now supports compilation from standard input and the arm eabi.

(Jun 17, 2005) TCC version 0.9.23 is out (Changelog). This is the first version with support for the Windows target.

(Nov 8, 2004) TCC version 0.9.22 is out (Changelog). Linux kernel compilation is 30% faster (10 seconds on a 2.4 GHz Pentium 4).

(Oct 25, 2004) TCC version 0.9.21 is out (Changelog). This version is the first one able to build a bootable Linux kernel with only a few patches to the kernel sources. As a demonstration, you can try the TCCBOOT boot loader. It is able to compile and boot a Linux kernel directly from its source code.

NOTE: if you want to compile the Linux kernel with TCC, you must use a custom build script as in TCCBOOT . I never tried to compile the Linux kernel with TinyCC and the standard Linux Makefiles.

Features

  • SMALL! You can compile and execute C code everywhere, for example on rescue disks (about 100KB for x86 TCC executable, including C preprocessor, C compiler, assembler and linker).
  • FAST! tcc generates x86 code. No byte code overhead. Compile, assemble and link several times faster than GCC.
  • UNLIMITED! Any C dynamic library can be used directly. TCC is heading torward full ISOC99 compliance. TCC can of course compile itself.
  • SAFE! tcc includes an optional memory and bound checker. Bound checked code can be mixed freely with standard code.
  • Compile and execute C source directly. No linking or assembly necessary. Full C preprocessor and GNU-like assembler included.
  • C script supported : just add '#!/usr/local/bin/tcc -run' at the first line of your C source, and execute it directly from the command line.
  • With libtcc, you can use TCC as a backend for dynamic code generation.

Download

Compilation Speed

Compilation speed for the Links Browser project. There are 76936 lines (including headers). 1950947 lines (67.2 MBytes) are compiled because the same headers are included in many files. TinyCC is about 9 times faster than GCC.

Compiler | Time(s) | lines/second | MBytes/second
TinyCC 0.9.22 | 2.27 | 859000 | 29.6
GCC 3.2 -O0 | 20.0 | 98000 | 3.4

Measures were done on a 2.4 GHz Pentium 4. Real time is measured. Compilation time includes compilation, assembly and linking.

More up to date tests are available: 1, 2, 3, 4.

Online Documentation

You want to help ?

Here are some suggestions:
  • Report bugs to the mailing list (and eventually fix them).

Links

  • TinyCC mailing list
  • Savannah project page and git repository
  • OTCC - The smallest self compiling pseudo C compiler
  • FFASN1 - My small but powerful ASN.1 compiler.
  • TinyCC fork by Rob Landley
  • LLVM Compiler Infrastructure
  • SmartEiffel - With TCC you can compile your Eiffel code faster
  • C-- - An intermediate language for compilers
  • The GNU C Compiler
  • The LCC Compiler
  • The Small Device C Compiler
  • Cyclone, A Safe Dialect of C
  • The D language
  • Programming in C
  • The Scriptometer evaluates various scripting languages (including TCC).

License

TCC is distributed under the GNU Lesser General Public License.
anybrowser
Copyright (c) 2001-2009 Fabrice Bellard
Fabrice Bellard - http://bellard.org/ - http://www.tinycc.org/


Tiny C Compiler — Wikipédia

﻿

Tiny C Compiler

Tiny C Compiler
Développeur | Fabrice Bellard
Dernière version | 0.9.26
æ#137;crit en | C Voir et modifier les données sur Wikidata
Type | compilateur
Licence | GNU LGPL
Site web | http://bellard.org/tcc
modifier Consultez la documentation du modèle

Tiny C Compiler (tcc, tout petit compilateur C) est un compilateur C x86, x86-64 et ARM complet développé par Fabrice Bellard. Sa dernière version (0.9.26, du 15 février 2013) peut être utilisée sur Unix, Linux et Microsoft Windows. Il est distribué sous la licence publique générale limitée GNU (GNU LGPL).

Le C ANSI et la nouvelle norme ISO C99 sont particulièrement bien supportés par tcc ; il est de plus compatible avec de nombreuses extensions GNU C, comme l'assembly inline. Cependant, rendre tcc entièrement conforme pourrait le ralentir de manière significative. Il ne fournit notamment pas les manipulations de tri-graphe (trigraph handling), les proper type, et les vérifications d'expressions.

Capacité

  • Il est petit : il peut compiler et exécuter du code C n'importe où, par exemple d'une disquette de secours (environ 100 Kio pour l'exécutable TCC, incluant le préprocesseur et compilateur C, l'assembleur et l'éditeur de liens).
  • Il est rapide : il génère du code x86 moyennement optimisé. Il compile, assemble et lie environ 9 fois plus vite que gcc.
  • Le C ANSI et la norme ISO C99 sont bien supportés. La seule caractéristique majeure de C99 manquante concerne les types complexes[1]. De nombreuses extensions GNU C sont gérées.
  • Il inclut un système de vérification de la mémoire et de ses accès. Ce système peut être ajouté au code utilisateur.
  • Il peut compiler et exécuter un fichier source C sans édition de liens ou assemblage.
  • Sous Linux, il peut être utilisé comme un interpréteur C : il suffit d'ajouter '#!/usr/local/bin/tcc -run' ænbsp; la première ligne du source C, et de l'exécuter directement depuis la console.
  • La bibliothèque libtcc permet ænbsp; n'importe quel programme de générer et exécuter dynamiquement du code.
  • Sa compilation ne nécessite que quelques bibliothèques.

Sa licence permet ænbsp; chacun de l'utiliser, modifier, et/ou redistribuer. Il peut être utilisé pour développer des logiciels open source ou propriétaire.

Histoire

tcc tient ses origines de OTCC [2] (Obsfucated Tiny C Compiler, Minuscule Compilateur C Assombri), un programme que Bellard a écrit pour gagner les IOCCC (Internation Obfuscated C Code Contest) en 2002. Depuis ce jour, il l'améliora et "dés-assombrit" le programme pour produire tcc.

Etat actuel

Le développement de tcc est ralenti car Fabrice Bellard est occupé ænbsp; d'autres projets. Cependant des versions modifiées existent, comme la Landley's Mercurial branch, les Dave Dodge's collection of unofficial tcc patches, Debian and kfreebsd downstream patches, et les patchs gcc de grischka[3].

La version 0.9.23 est sujette ænbsp; une vulnérabilité classée CVE-2006-0635 ou Open Source Vulnerability Database vulnerability 22956. Le rapport est que tcc "contient une faille qui peut avoir des complications quant ænbsp; la sécurité du programme compilé avec ce dernier. Le compilateur ne peut retourner une valeur non signée de l'opérateur sizeof , ayant pour conséquence un débordement potentiel des entiers dans les objets qu'il compile." Cette faille a été corrigé dans le fork de Rob Landley puis incorporé dans la version officielle de tcc pour la version 0.9.24.

La version 0.9.25 est la première version ænbsp; supporter le 64 bits.

TCC a une mailing list active, et la version courante de Bellard est accessible depuis git.

Utilisation

Les utilisations les plus connues de tcc sont :

  • TCCBOOT, un programme où tcc charge et lance un noyau linux ænbsp; partir des sources en environ 15 secondes sur un processeur Pentium 4 ænbsp; 2.4 GHz. Le déroulement se passe en trois phases : TCCBOOT charge les sources du noyau Linux depuis le disque dur, place le code généré en mémoire et passe la main au noyau Linux. Pour ce faire, le processus de construction de Linux nécessite quelques modifications.
  • Il a été utilisé pour démontrer une défense contre les attaques de porte dérobée [4].
  • Cinpy est une bibliothèque Python qui permet d'implémenter du code C dans des modules Python. Ce code est compilé ænbsp; chaud avec tcc.

Références

  1. ? TODO list [ archive ]. Les tableaux ænbsp; longueur variable (VLA) ont été ajoutés dans TCC 0.9.26.[1] [ archive ]
  2. ? Bellard, Fabrice. Obfuscated Tiny C Compiler [ archive ]
  3. ? grischka, http://lists.gnu.org/archive/html/tinycc-devel/2005-09/msg00054.html [ archive ] GCC by TCC (some fixes)], 29 Sep 2005
  4. ? Wheeler, David A. Countering Trusting Trust through Diverse Double-Compiling [ archive ]. ACSAC.

Voir aussi

Liens externes

  • (en) Le site officiel de tcc
  • (en) La page de tcc sur savannah
  • (en) La page de Fabrice Bellard
  • (fr) « Auto-compiler » son noyau au démarrage avec TCCBoot
  • (en) Le boot loader TCCBoot de Fabrice Bellard
  • (en) Version modifiée de Rob Landley (reference)


TCC - OSDev Wiki

TCC

From OSDev Wiki
Jump to: navigation, search

This page is under construction! This page is a work in progress and may thus be incomplete. Its content may be changed in the near future.

This article describes how to make a sample ELF kernel with FASM and Tiny C Compiler (aka TCC). It is also possible to use NASM (Bare_Bones_with_NASM). TCC is a small and fast C compiler, which produces x86, x86_64 or ARM code, and generates PE or ELF executables. TCC is heading toward full ISOC99 compliance, and can compile itself, like FASM.

TCC includes also a linker and an assembler (only x86). But this assembler is limited: no 16/64-bit support, instructions up to MMX are supported.

Note: The Windows version of TCC doesn't produces ELF executables, but only object files. You need to recompile TCC without PE support, if you want to use this tutorial on Windows. You can skip this step if you aren't using Windows.

Contents

[hide]
  • 1 Building TCC with ELF support
  • 2 A small kernel example
    • 2.1 start32.asm
    • 2.2 kernel.c
  • 3 Compiling and linking
  • 4 Inline Assembly
  • 5 GDT and struct warning
  • 6 Inline Function Warning

Building TCC with ELF support

1. Download TCC sources and 32-bit TCC and (if you have a 64-bit OS) 64-bit TCC.

2. Extract the source folder tcc-0.9.26.

3. Save the 32-bit tcc files to a folder called "win32" in the location containing tcc-0.9.26. If you have a 64-bit OS, also create a win64 folder, and save the 64-bit files to a folder called "win64" in the same location.

4. Open Notepad or another text editor, and enter this:

@echo off

set \p VERSION = < .VERSION
echo > config.h #define TCC_VERSION "%VERSION%"

set targetP=I386
set B=32
goto begin

:x86_64
set targetP=X86_64
set B=64
goto begin

:begin
set targetF=PE
set CC=..\win%B%\tcc.exe -O0 -s -fno-strict-aliasing
set P=%B%

:start
if %targetF%==ELF set P=%B%-elf
set target=-DTCC_TARGET_%targetF% -DTCC_TARGET_%targetP%

:tools
%CC% %target% win%P%\tools\tiny_impdef.c -o win%P%\tiny_impdef.exe
%CC% %target% win%P%\tools\tiny_libmaker.c -o win%P%\tiny_libmaker.exe

:libtcc
if not exist win%P%\libtcc\nul mkdir win%P%\libtcc
copy libtcc.h win%P%\libtcc\libtcc.h
%CC% %target% -shared -DLIBTCC_AS_DLL -DONE_SOURCE libtcc.c -o win%P%\libtcc.dll
win%P%\tiny_impdef win%P%\libtcc.dll -o win%P%\libtcc\libtcc.def

:tcc
%CC% %target% tcc.c -o win%P%\tcc.exe -ltcc -Lwin%P%\libtcc

:copy_std_includes
copy include\*.h win%P%\include

:libtcc1.a
win%B%\tcc %target% -c lib\libtcc1.c -o win%P%\libtcc1.o
win%B%\tcc %target% -c win%P%\lib\crt1.c -o win%P%\crt1.o
win%B%\tcc %target% -c win%P%\lib\wincrt1.c -o win%P%\wincrt1.o
win%B%\tcc %target% -c win%P%\lib\dllcrt1.c -o win%P%\dllcrt1.o
win%B%\tcc %target% -c win%P%\lib\dllmain.c -o win%P%\dllmain.o
win%B%\tcc %target% -c win%P%\lib\chkstk.S -o win%P%\chkstk.o
goto lib%B%

:lib32
win%B%\tcc %target% -c lib\alloca86.S -o win%P%\alloca86.o
win%B%\tcc %target% -c lib\alloca86-bt.S -o win%P%\alloca86-bt.o
win%B%\tcc %target% -c lib\bcheck.c -o win%P%\bcheck.o
win%P%\tiny_libmaker win%P%\lib\libtcc1.a win%P%\libtcc1.o win%P%\alloca86.o win%P%\alloca86-bt.o win%P%\crt1.o win%P%\wincrt1.o win%P%\dllcrt1.o win%P%\dllmain.o win%P%\chkstk.o win%P%\bcheck.o
@goto the_end

:lib64
win%P%\tcc %target% -c lib\alloca86_64.S -o win%P%\alloca86_64.o
win%P%\tiny_libmaker win%P%\lib\libtcc1.a win%P%\libtcc1.o win%P%\alloca86_64.o win%P%\crt1.o win%P%\wincrt1.o win%P%\dllcrt1.o win%P%\dllmain.o win%P%\chkstk.o

:the_end
del win%P%\*.o

@if %targetF%==PE (
    @set targetF=ELF
    @goto start
)

@if %B%==64 goto finished
@if _%PROCESSOR_ARCHITEW6432%_==_AMD64_ goto x86_64
@if _%PROCESSOR_ARCHITECTURE%_==_AMD64_ goto x86_64

:finished

5. Save to tcc-0.9.26 with any name you want, but the extension MUST be .bat. If you use notepad, you will have to change the type from "Text Documents" to "All Files".

6. Run the script, make sure everything compiled correctly (note that there may be warnings about assignments from incompatible pointer types and bound checking not supporting malloc in a certain environment, but these are okay), and inside win32-elf you should have a working ELF compiler. You should also have win32 and win64 for 32-bit and 64-bit PE compilers, and a 64-bit ELF compiler in win64-elf. Note: The 64-bit compilers won't be compiled on a non-64 bit OS. If there are errors compiling TCC, just change the "@echo off" to "@echo on" and run the script again to see where things went wrong.

A small kernel example

This little example builds a small kernel in ELF format, which can be booted by Grub.

start32.asm

;  Tutorial: A small kernel with Fasm & TCC
;  By Tommy.

        format elf
        use32

;
; Equates
;
MULTIBOOT_PAGE_ALIGN	    equ (1 shl 0)
MULTIBOOT_MEMORY_INFO	    equ (1 shl 1)
MULTIBOOT_AOUT_KLUDGE	    equ (1 shl 16)
MULTIBOOT_HEADER_MAGIC	    equ 0x1BADB002
MULTIBOOT_HEADER_FLAGS	    equ MULTIBOOT_PAGE_ALIGN or MULTIBOOT_MEMORY_INFO
MULTIBOOT_CHECKSUM          equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)

        section '.text' executable
;
; Multiboot header
;
dd MULTIBOOT_HEADER_MAGIC
dd MULTIBOOT_HEADER_FLAGS
dd MULTIBOOT_CHECKSUM

;
; Kernel entry point.
;
        public  _start
        extrn   kmain
_start:
        ; Call the main kernel function.
        call    kmain

@@:
        jmp     @b

kernel.c

/*  Tutorial: A small kernel with Fasm & TCC
 *  By Tommy.
 */

/*
 * Main kernel function.
 */
void
kmain (void)
{
    *((unsigned char *) 0xB8000) = 'H';
    *((unsigned char *) 0xB8001) = 0x1F;
    *((unsigned char *) 0xB8002) = 'E';
    *((unsigned char *) 0xB8003) = 0x1F;
    *((unsigned char *) 0xB8004) = 'L';
    *((unsigned char *) 0xB8005) = 0x1F;
    *((unsigned char *) 0xB8006) = 'L';
    *((unsigned char *) 0xB8007) = 0x1F;
    *((unsigned char *) 0xB8008) = 'O';
    *((unsigned char *) 0xB8009) = 0x1F;
}

Compiling and linking

Assemble start32.asm with:

fasm start32.asm

Compile kernel.c with:

tcc -c kernel.c

Then link the whole thing with:

tcc -nostdlib -Wl,-Ttext,0x100000 start32.o kernel.o -o kernel-i386.elf

If you would prefer it in binary form, for example, if you're using your own bootloader that doesn't support ELF, link it with this:

tcc -nostdlib -Wl,-Ttext,0x100000 -Wl,--oformat,binary -static start32.o kernel.o -o kernel-i386.bin

That's all!

Inline Assembly

TCC supports inline GAS syntax assembly like GCC:

__asm__ __volatile__("hlt");

You can use this to your benefit for many things, such as debugging in Bochs:

#define breakpoint() __asm__ __volatile__("xchg %bx, %bx");

void bochs_print (char *string) {
    char *c = string;
    while (*c != '\0') {
        outb(0xE9, *c); // may be outportb
        c++;
    }
}

Then adding this to your bochsrc.bxrc file in a text editor:

port_e9_hack: enabled=1
magic_break: enabled=1

And from boch's install location, executing bochsdbg.exe instead of bochs.exe.

GDT and struct warning

According to Fabrice Bellard, the creator of TCC, and (painfully) tested to be true: "In TCC 'packed' is supported only for structure fields or variable declarations, not for a whole structure. So a solution for you is to add it to each field of the packed structure." So if you use structs to store your GDT entries or GDTR, beware, you will encounter issues loading your GDT if you don't specify the packing of structures correctly. When creating structures, use something like this:

// We use the attribute 'packed' to tell TCC not to change any of the alignment in the structure.
struct some_struct {
   unsigned char a __attribute__((packed));
   unsigned char b __attribute__((packed));
} __attribute__((packed));
// This last attribute can be kept, it won't interfere with the compilation or output, so it may be
// useful to retain compatilbity with GCC, as long as the above attributes don't interfere with GCC.

Instead of this:

// We use the attribute 'packed' to tell GCC not to change any of the alignment in the structure.
struct some_struct {
   unsigned char a;
   unsigned char b;
} __attribute__((packed));

Inline Function Warning

TCC doesn't support function inlining, because the 'inline' keyword is ignored, so if a function needs to be inlined, you must use defines instead.

Retrieved from "http://wiki.osdev.org/index.php?title=TCC&oldid=16406"
Category:
  • In Progress
Personal tools
  • Log in
Namespaces
  • Page
  • Discussion
Variants
Views
  • Read
  • View source
  • View history
Actions
Navigation
  • Main Page
  • Forums
  • FAQ
  • OS Projects
  • Random page
About
  • This site
  • Joining
  • Editing help
  • Recent changes
Toolbox
  • What links here
  • Related changes
  • Special pages
  • Printable version
  • Permanent link
  • This page was last modified on 27 May 2014, at 01:57.
  • This page has been accessed 22,595 times.
  • Privacy policy
  • About OSDev Wiki
  • Disclaimers
  • Powered by MediaWiki


Tiny C Compiler Reference Docume

Tiny C Compiler Reference Documentation

Table of Contents

  • 1. Introduction
  • 2. Command line invocation
    • 2.1 Quick start
    • 2.2 Option summary
  • 3. C language support
    • 3.1 ANSI C
    • 3.2 ISOC99 extensions
    • 3.3 GNU C extensions
    • 3.4 TinyCC extensions
  • 4. TinyCC Assembler
    • 4.1 Syntax
    • 4.2 Expressions
    • 4.3 Labels
    • 4.4 Directives
    • 4.5 X86 Assembler
  • 5. TinyCC Linker
    • 5.1 ELF file generation
    • 5.2 ELF file loader
    • 5.3 PE-i386 file generation
    • 5.4 GNU Linker Scripts
  • 6. TinyCC Memory and Bound checks
  • 7. The libtcc library
  • 8. Developer's guide
    • 8.1 File reading
    • 8.2 Lexer
    • 8.3 Parser
    • 8.4 Types
    • 8.5 Symbols
    • 8.6 Sections
    • 8.7 Code generation
      • 8.7.1 Introduction
      • 8.7.2 The value stack
      • 8.7.3 Manipulating the value stack
      • 8.7.4 CPU dependent code generation
    • 8.8 Optimizations done


Tiny C Compiler Reference Documentation

Table of Contents

  • 1. Introduction
  • 2. Command line invocation
    • 2.1 Quick start
    • 2.2 Option summary
  • 3. C language support
    • 3.1 ANSI C
    • 3.2 ISOC99 extensions
    • 3.3 GNU C extensions
    • 3.4 TinyCC extensions
  • 4. TinyCC Assembler
    • 4.1 Syntax
    • 4.2 Expressions
    • 4.3 Labels
    • 4.4 Directives
    • 4.5 X86 Assembler
  • 5. TinyCC Linker
    • 5.1 ELF file generation
    • 5.2 ELF file loader
    • 5.3 PE-i386 file generation
    • 5.4 GNU Linker Scripts
  • 6. TinyCC Memory and Bound checks
  • 7. The libtcc library
  • 8. Developer's guide
    • 8.1 File reading
    • 8.2 Lexer
    • 8.3 Parser
    • 8.4 Types
    • 8.5 Symbols
    • 8.6 Sections
    • 8.7 Code generation
      • 8.7.1 Introduction
      • 8.7.2 The value stack
      • 8.7.3 Manipulating the value stack
      • 8.7.4 CPU dependent code generation
    • 8.8 Optimizations done
  • Concept Index

1. Introduction

TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C compilers, it is meant to be self-relying: you do not need an external assembler or linker because TCC does that for you.

TCC compiles so fast that even for big projects Makefiles may not be necessary.

TCC not only supports ANSI C, but also most of the new ISO C99 standard and many GNUC extensions including inline assembly.

TCC can also be used to make C scripts, i.e. pieces of C source that you run as a Perl or Python script. Compilation is so fast that your script will be as fast as if it was an executable.

TCC can also automatically generate memory and bound checks (see section 6. TinyCC Memory and Bound checks) while allowing all C pointers operations. TCC can do these checks even if non patched libraries are used.

With libtcc, you can use TCC as a backend for dynamic code generation (see section 7. The libtcc library).

TCC mainly supports the i386 target on Linux and Windows. There are alpha ports for the ARM (arm-tcc) and the TMS320C67xx targets (c67-tcc). More information about the ARM port is available at http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html.

For usage on Windows, see also tcc-win32.txt.

2. Command line invocation

2.1 Quick start

usage: tcc [options] [infile1 infile2...] [`-run' infile args...]

TCC options are a very much like gcc options. The main difference is that TCC can also execute directly the resulting program and give it runtime arguments.

Here are some examples to understand the logic:

`tcc -run a.c'

Compile `a.c' and execute it directly

`tcc -run a.c arg1'

Compile a.c and execute it directly. arg1 is given as first argument to the main() of a.c.

`tcc a.c -run b.c arg1'

Compile `a.c' and `b.c', link them together and execute them. arg1 is given as first argument to the main() of the resulting program.

`tcc -o myprog a.c b.c'

Compile `a.c' and `b.c', link them and generate the executable `myprog'.

`tcc -o myprog a.o b.o'

link `a.o' and `b.o' together and generate the executable `myprog'.

`tcc -c a.c'

Compile `a.c' and generate object file `a.o'.

`tcc -c asmfile.S'

Preprocess with C preprocess and assemble `asmfile.S' and generate object file `asmfile.o'.

`tcc -c asmfile.s'

Assemble (but not preprocess) `asmfile.s' and generate object file `asmfile.o'.

`tcc -r -o ab.o a.c b.c'

Compile `a.c' and `b.c', link them together and generate the object file `ab.o'.

Scripting:

TCC can be invoked from scripts, just as shell scripts. You just need to add #!/usr/local/bin/tcc -run at the start of your C source:

#!/usr/local/bin/tcc -run
#include <stdio.h>

int main()
{
    printf("Hello World\n");
    return 0;
}

TCC can read C source code from standard input when `-' is used in place of `infile'. Example:

echo 'main(){puts("hello");}' | tcc -run -

2.2 Option summary

General Options:

`-v'

Display current TCC version, increase verbosity.

`-c'

Generate an object file (`-o' option must also be given).

`-o outfile'

Put object file, executable, or dll into output file `outfile'.

`-Bdir'

Set the path where the tcc internal libraries can be found (default is `PREFIX/lib/tcc').

`-bench'

Output compilation statistics.

`-run source [args...]'

Compile file source and run it with the command line arguments args. In order to be able to give more than one argument to a script, several TCC options can be given after the `-run' option, separated by spaces. Example:

tcc "-run -L/usr/X11R6/lib -lX11" ex4.c

In a script, it gives the following header:

#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>
int main(int argc, char **argv)
{
    ...
}

Preprocessor options:

`-Idir'

Specify an additional include path. Include paths are searched in the order they are specified. System include paths are always searched after. The default system include paths are: `/usr/local/include', `/usr/include' and `PREFIX/lib/tcc/include'. (`PREFIX' is usually `/usr' or `/usr/local').

`-Dsym[=val]'

Define preprocessor symbol `sym' to val. If val is not present, its value is `1'. Function-like macros can also be defined: `-DF(a)=a+1'

`-Usym'

Undefine preprocessor symbol `sym'.

Compilation flags:

Note: each of the following warning options has a negative form beginning with `-fno-'.

`-funsigned-char'

Let the char type be unsigned.

`-fsigned-char'

Let the char type be signed.

`-fno-common'

Do not generate common symbols for uninitialized data.

`-fleading-underscore'

Add a leading underscore at the beginning of each C symbol.

Warning options:

`-w'

Disable all warnings.

Note: each of the following warning options has a negative form beginning with `-Wno-'.

`-Wimplicit-function-declaration'

Warn about implicit function declaration.

`-Wunsupported'

Warn about unsupported GCC features that are ignored by TCC.

`-Wwrite-strings'

Make string constants be of type const char * instead of char *.

`-Werror'

Abort compilation if warnings are issued.

`-Wall'

Activate all warnings, except `-Werror', `-Wunusupported' and `-Wwrite-strings'.

Linker options:

`-Ldir'

Specify an additional static library path for the `-l' option. The default library paths are `/usr/local/lib', `/usr/lib' and `/lib'.

`-lxxx'

Link your program with dynamic library libxxx.so or static library libxxx.a. The library is searched in the paths specified by the `-L' option.

`-shared'

Generate a shared library instead of an executable (`-o' option must also be given).

`-static'

Generate a statically linked executable (default is a shared linked executable) (`-o' option must also be given).

`-rdynamic'

Export global symbols to the dynamic linker. It is useful when a library opened with dlopen() needs to access executable symbols.

`-r'

Generate an object file combining all input files (`-o' option must also be given).

`-Wl,-Ttext,address'

Set the start of the .text section to address.

`-Wl,--oformat,fmt'

Use fmt as output format. The supported output formats are:

elf32-i386

ELF output format (default)

binary

Binary image (only for executable output)

coff

COFF output format (only for executable output for TMS320C67xx target)

Debugger options:

`-g'

Generate run time debug information so that you get clear run time error messages: test.c:68: in function 'test5()': dereferencing invalid pointer instead of the laconic Segmentation fault.

`-b'

Generate additional support code to check memory allocations and array/pointer bounds. `-g' is implied. Note that the generated code is slower and bigger in this case.

`-bt N'

Display N callers in stack traces. This is useful with `-g' or `-b'.

Note: GCC options `-Ox', `-fx' and `-mx' are ignored.

3. C language support

3.1 ANSI C

TCC implements all the ANSI C standard, including structure bit fields and floating point numbers (long double, double, and float fully supported).

3.2 ISOC99 extensions

TCC implements many features of the new C standard: ISO C99. Currently missing items are: complex and imaginary numbers and variable length arrays.

Currently implemented ISOC99 features:

  • 64 bit long long types are fully supported.
  • The boolean type _Bool is supported.
  • __func__ is a string variable containing the current function name.
  • Variadic macros: __VA_ARGS__ can be used for function-like macros:
·
·                    #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__)

dprintf can then be used with a variable number of parameters.

  • Declarations can appear anywhere in a block (as in C++).
  • Array and struct/union elements can be initialized in any order by using designators:
·
·                    struct { int x, y; } st[10] = { [0].x = 1, [0].y = 2 };
·
·                    int tab[10] = { 1, 2, [5] = 5, [9] = 9};
  • Compound initializers are supported:
·
·                    int *p = (int []){ 1, 2, 3 };

to initialize a pointer pointing to an initialized array. The same works for structures and strings.

  • Hexadecimal floating point constants are supported:
·
·                          double d = 0x1234p10;

is the same as writing

          double d = 4771840.0;
  • inline keyword is ignored.
  • restrict keyword is ignored.

3.3 GNU C extensions

TCC implements some GNU C extensions:

  • array designators can be used without '=':
·
·                    int a[10] = { [0] 1, [5] 2, 3, 4 };
  • Structure field designators can be a label:
·
·                    struct { int x, y; } st = { x: 1, y: 1};

instead of

    struct { int x, y; } st = { .x = 1, .y = 1};
  • \e is ASCII character 27.
  • case ranges : ranges can be used in cases:
·
·                    switch(a) {
·                    case 1 ... 9:
·                          printf("range 1 to 9\n");
·                          break;
·                    default:
·                          printf("unexpected\n");
·                          break;
·                    }
  • The keyword __attribute__ is handled to specify variable or function attributes. The following attributes are supported:
    • aligned(n): align a variable or a structure field to n bytes (must be a power of two).
    • packed: force alignment of a variable or a structure field to 1.
    • section(name): generate function or data in assembly section name (name is a string containing the section name) instead of the default section.
    • unused: specify that the variable or the function is unused.
    • cdecl: use standard C calling convention (default).
    • stdcall: use Pascal-like calling convention.
    • regparm(n): use fast i386 calling convention. n must be between 1 and 3. The first n function parameters are respectively put in registers %eax, %edx and %ecx.
    • dllexport: export function from dll/executable (win32 only)

Here are some examples:

    int a __attribute__ ((aligned(8), section(".mysection")));

align variable a to 8 bytes and put it in section .mysection.

    int my_add(int a, int b) __attribute__ ((section(".mycodesection")))
    {
        return a + b;
    }

generate function my_add in section .mycodesection.

  • GNU style variadic macros:
·
·                    #define dprintf(fmt, args...) printf(fmt, ## args)
·
·                    dprintf("no arg\n");
·                    dprintf("one arg %d\n", 1);
  • __FUNCTION__ is interpreted as C99 __func__ (so it has not exactly the same semantics as string literal GNUC where it is a string literal).
  • The __alignof__ keyword can be used as sizeof to get the alignment of a type or an expression.
  • The typeof(x) returns the type of x. x is an expression or a type.
  • Computed gotos: &&label returns a pointer of type void * on the goto label label. goto *expr can be used to jump on the pointer resulting from expr.
  • Inline assembly with asm instruction:
·
·                static inline void * my_memcpy(void * to, const void * from, size_t n)
·                {
·                int d0, d1, d2;
·                __asm__ __volatile__(
·                        "rep ; movsl\n\t"
·                        "testb $2,%b4\n\t"
·                        "je 1f\n\t"
·                        "movsw\n"
·                        "1:\ttestb $1,%b4\n\t"
·                        "je 2f\n\t"
·                        "movsb\n"
·                        "2:"
·                        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
·                        :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
·                        : "memory");
·                return (to);
·                }

TCC includes its own x86 inline assembler with a gas-like (GNU assembler) syntax. No intermediate files are generated. GCC 3.x named operands are supported.

  • __builtin_types_compatible_p() and __builtin_constant_p() are supported.
  • #pragma pack is supported for win32 compatibility.

3.4 TinyCC extensions

  • __TINYC__ is a predefined macro to 1 to indicate that you use TCC.
  • #! at the start of a line is ignored to allow scripting.
  • Binary digits can be entered (0b101 instead of 5).
  • __BOUNDS_CHECKING_ON is defined if bound checking is activated.

4. TinyCC Assembler

Since version 0.9.16, TinyCC integrates its own assembler. TinyCC assembler supports a gas-like syntax (GNU assembler). You can desactivate assembler support if you want a smaller TinyCC executable (the C compiler does not rely on the assembler).

TinyCC Assembler is used to handle files with `.S' (C preprocessed assembler) and `.s' extensions. It is also used to handle the GNU inline assembler with the asm keyword.

4.1 Syntax

TinyCC Assembler supports most of the gas syntax. The tokens are the same as C.

  • C and C++ comments are supported.
  • Identifiers are the same as C, so you cannot use '.' or '$'.
  • Only 32 bit integer numbers are supported.

4.2 Expressions

  • Integers in decimal, octal and hexa are supported.
  • Unary operators: +, -, ~.
  • Binary operators in decreasing priority order:
    1. *, /, %
    2. &, |, ^
    3. +, -
  • A value is either an absolute number or a label plus an offset. All operators accept absolute values except '+' and '-'. '+' or '-' can be used to add an offset to a label. '-' supports two labels only if they are the same or if they are both defined and in the same section.

4.3 Labels

  • All labels are considered as local, except undefined ones.
  • Numeric labels can be used as local gas-like labels. They can be defined several times in the same source. Use 'b' (backward) or 'f' (forward) as suffix to reference them:
·
·                 1:
·                      jmp 1b /* jump to '1' label before */
·                      jmp 1f /* jump to '1' label after */
·                 1:

4.4 Directives

All directives are preceeded by a '.'. The following directives are supported:

  • .align n[,value]
  • .skip n[,value]
  • .space n[,value]
  • .byte value1[,...]
  • .word value1[,...]
  • .short value1[,...]
  • .int value1[,...]
  • .long value1[,...]
  • .quad immediate_value1[,...]
  • .globl symbol
  • .global symbol
  • .section section
  • .text
  • .data
  • .bss
  • .fill repeat[,size[,value]]
  • .org n
  • .previous
  • .string string[,...]
  • .asciz string[,...]
  • .ascii string[,...]

4.5 X86 Assembler

All X86 opcodes are supported. Only ATT syntax is supported (source then destination operand order). If no size suffix is given, TinyCC tries to guess it from the operand sizes.

Currently, MMX opcodes are supported but not SSE ones.

5. TinyCC Linker

5.1 ELF file generation

TCC can directly output relocatable ELF files (object files), executable ELF files and dynamic ELF libraries without relying on an external linker.

Dynamic ELF libraries can be output but the C compiler does not generate position independent code (PIC). It means that the dynamic library code generated by TCC cannot be factorized among processes yet.

TCC linker eliminates unreferenced object code in libraries. A single pass is done on the object and library list, so the order in which object files and libraries are specified is important (same constraint as GNU ld). No grouping options (`--start-group' and `--end-group') are supported.

5.2 ELF file loader

TCC can load ELF object files, archives (.a files) and dynamic libraries (.so).

5.3 PE-i386 file generation

TCC for Windows supports the native Win32 executable file format (PE-i386). It generates EXE files (console and gui) and DLL files.

For usage on Windows, see also tcc-win32.txt.

5.4 GNU Linker Scripts

Because on many Linux systems some dynamic libraries (such as `/usr/lib/libc.so') are in fact GNU ld link scripts (horrible!), the TCC linker also supports a subset of GNU ld scripts.

The GROUP and FILE commands are supported. OUTPUT_FORMAT and TARGET are ignored.

Example from `/usr/lib/libc.so':

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )

6. TinyCC Memory and Bound checks

This feature is activated with the `-b' (see section 2. Command line invocation).

Note that pointer size is unchanged and that code generated with bound checks is fully compatible with unchecked code. When a pointer comes from unchecked code, it is assumed to be valid. Even very obscure C code with casts should work correctly.

For more information about the ideas behind this method, see http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html.

Here are some examples of caught errors:

Invalid range with standard string function:

{
    char tab[10];
    memset(tab, 0, 11);
}

Out of bounds-error in global or local arrays:

{
    int tab[10];
    for(i=0;i<11;i++) {
        sum += tab[i];
    }
}

Out of bounds-error in malloc'ed data:

{
    int *tab;
    tab = malloc(20 * sizeof(int));
    for(i=0;i<21;i++) {
        sum += tab4[i];
    }
    free(tab);
}

Access of freed memory:

{
    int *tab;
    tab = malloc(20 * sizeof(int));
    free(tab);
    for(i=0;i<20;i++) {
        sum += tab4[i];
    }
}

Double free:

{
    int *tab;
    tab = malloc(20 * sizeof(int));
    free(tab);
    free(tab);
}

7. The libtcc library

The libtcc library enables you to use TCC as a backend for dynamic code generation.

Read the `libtcc.h' to have an overview of the API. Read `libtcc_test.c' to have a very simple example.

The idea consists in giving a C string containing the program you want to compile directly to libtcc. Then you can access to any global symbol (function or variable) defined.

8. Developer's guide

This chapter gives some hints to understand how TCC works. You can skip it if you do not intend to modify the TCC code.

8.1 File reading

The BufferedFile structure contains the context needed to read a file, including the current line number. tcc_open() opens a new file and tcc_close() closes it. inp() returns the next character.

8.2 Lexer

next() reads the next token in the current file. next_nomacro() reads the next token without macro expansion.

tok contains the current token (see TOK_xxx) constants. Identifiers and keywords are also keywords. tokc contains additional infos about the token (for example a constant value if number or string token).

8.3 Parser

The parser is hardcoded (yacc is not necessary). It does only one pass, except:

  • For initialized arrays with unknown size, a first pass is done to count the number of elements.
  • For architectures where arguments are evaluated in reverse order, a first pass is done to reverse the argument order.

8.4 Types

The types are stored in a single 'int' variable. It was choosen in the first stages of development when tcc was much simpler. Now, it may not be the best solution.

#define VT_INT        0  /* integer type */
#define VT_BYTE       1  /* signed byte type */
#define VT_SHORT      2  /* short type */
#define VT_VOID       3  /* void type */
#define VT_PTR        4  /* pointer */
#define VT_ENUM       5  /* enum definition */
#define VT_FUNC       6  /* function type */
#define VT_STRUCT     7  /* struct/union definition */
#define VT_FLOAT      8  /* IEEE float */
#define VT_DOUBLE     9  /* IEEE double */
#define VT_LDOUBLE   10  /* IEEE long double */
#define VT_BOOL      11  /* ISOC99 boolean type */
#define VT_LLONG     12  /* 64 bit integer */
#define VT_LONG      13  /* long integer (NEVER USED as type, only
                            during parsing) */
#define VT_BTYPE      0x000f /* mask for basic type */
#define VT_UNSIGNED   0x0010  /* unsigned type */
#define VT_ARRAY      0x0020  /* array type (also has VT_PTR) */
#define VT_BITFIELD   0x0040  /* bitfield modifier */

#define VT_STRUCT_SHIFT 16   /* structure/enum name shift (16 bits left) */

When a reference to another type is needed (for pointers, functions and structures), the 32 - VT_STRUCT_SHIFT high order bits are used to store an identifier reference.

The VT_UNSIGNED flag can be set for chars, shorts, ints and long longs.

Arrays are considered as pointers VT_PTR with the flag VT_ARRAY set.

The VT_BITFIELD flag can be set for chars, shorts, ints and long longs. If it is set, then the bitfield position is stored from bits VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11.

VT_LONG is never used except during parsing.

During parsing, the storage of an object is also stored in the type integer:

#define VT_EXTERN  0x00000080  /* extern definition */
#define VT_STATIC  0x00000100  /* static variable */
#define VT_TYPEDEF 0x00000200  /* typedef definition */

8.5 Symbols

All symbols are stored in hashed symbol stacks. Each symbol stack contains Sym structures.

Sym.v contains the symbol name (remember an idenfier is also a token, so a string is never necessary to store it). Sym.t gives the type of the symbol. Sym.r is usually the register in which the corresponding variable is stored. Sym.c is usually a constant associated to the symbol.

Four main symbol stacks are defined:

define_stack

for the macros (#defines).

global_stack

for the global variables, functions and types.

local_stack

for the local variables, functions and types.

global_label_stack

for the local labels (for goto).

label_stack

for GCC block local labels (see the __label__ keyword).

sym_push() is used to add a new symbol in the local symbol stack. If no local symbol stack is active, it is added in the global symbol stack.

sym_pop(st,b) pops symbols from the symbol stack st until the symbol b is on the top of stack. If b is NULL, the stack is emptied.

sym_find(v) return the symbol associated to the identifier v. The local stack is searched first from top to bottom, then the global stack.

8.6 Sections

The generated code and datas are written in sections. The structure Section contains all the necessary information for a given section. new_section() creates a new section. ELF file semantics is assumed for each section.

The following sections are predefined:

text_section

is the section containing the generated code. ind contains the current position in the code section.

data_section

contains initialized data

bss_section

contains uninitialized data

bounds_section

lbounds_section

are used when bound checking is activated

stab_section

stabstr_section

are used when debugging is actived to store debug information

symtab_section

strtab_section

contain the exported symbols (currently only used for debugging).

8.7 Code generation

8.7.1 Introduction

The TCC code generator directly generates linked binary code in one pass. It is rather unusual these days (see gcc for example which generates text assembly), but it can be very fast and surprisingly little complicated.

The TCC code generator is register based. Optimization is only done at the expression level. No intermediate representation of expression is kept except the current values stored in the value stack.

On x86, three temporary registers are used. When more registers are needed, one register is spilled into a new temporary variable on the stack.

8.7.2 The value stack

When an expression is parsed, its value is pushed on the value stack (vstack). The top of the value stack is vtop. Each value stack entry is the structure SValue.

SValue.t is the type. SValue.r indicates how the value is currently stored in the generated code. It is usually a CPU register index (REG_xxx constants), but additional values and flags are defined:

#define VT_CONST     0x00f0
#define VT_LLOCAL    0x00f1
#define VT_LOCAL     0x00f2
#define VT_CMP       0x00f3
#define VT_JMP       0x00f4
#define VT_JMPI      0x00f5
#define VT_LVAL      0x0100
#define VT_SYM       0x0200
#define VT_MUSTCAST  0x0400
#define VT_MUSTBOUND 0x0800
#define VT_BOUNDED   0x8000
#define VT_LVAL_BYTE     0x1000
#define VT_LVAL_SHORT    0x2000
#define VT_LVAL_UNSIGNED 0x4000
#define VT_LVAL_TYPE     (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)

VT_CONST

indicates that the value is a constant. It is stored in the union SValue.c, depending on its type.

VT_LOCAL

indicates a local variable pointer at offset SValue.c.i in the stack.

VT_CMP

indicates that the value is actually stored in the CPU flags (i.e. the value is the consequence of a test). The value is either 0 or 1. The actual CPU flags used is indicated in SValue.c.i. If any code is generated which destroys the CPU flags, this value MUST be put in a normal register.

VT_JMP

VT_JMPI

indicates that the value is the consequence of a conditional jump. For VT_JMP, it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted. These values are used to compile the || and && logical operators. If any code is generated, this value MUST be put in a normal register. Otherwise, the generated code won't be executed if the jump is taken.

VT_LVAL

is a flag indicating that the value is actually an lvalue (left value of an assignment). It means that the value stored is actually a pointer to the wanted value. Understanding the use VT_LVAL is very important if you want to understand how TCC works.

VT_LVAL_BYTE

VT_LVAL_SHORT

VT_LVAL_UNSIGNED

if the lvalue has an integer type, then these flags give its real type. The type alone is not enough in case of cast optimisations.

VT_LLOCAL

is a saved lvalue on the stack. VT_LLOCAL should be eliminated ASAP because its semantics are rather complicated.

VT_MUSTCAST

indicates that a cast to the value type must be performed if the value is used (lazy casting).

VT_SYM

indicates that the symbol SValue.sym must be added to the constant.

VT_MUSTBOUND

VT_BOUNDED

are only used for optional bound checking.

8.7.3 Manipulating the value stack

vsetc() and vset() pushes a new value on the value stack. If the previous vtop was stored in a very unsafe place(for example in the CPU flags), then some code is generated to put the previous vtop in a safe storage.

vpop() pops vtop. In some cases, it also generates cleanup code (for example if stacked floating point registers are used as on x86).

The gv(rc) function generates code to evaluate vtop (the top value of the stack) into registers. rc selects in which register class the value should be put. gv() is the most important function of the code generator.

gv2() is the same as gv() but for the top two stack entries.

8.7.4 CPU dependent code generation

See the `i386-gen.c' file to have an example.

load()

must generate the code needed to load a stack value into a register.

store()

must generate the code needed to store a register into a stack value lvalue.

gfunc_start()

gfunc_param()

gfunc_call()

should generate a function call

gfunc_prolog()

gfunc_epilog()

should generate a function prolog/epilog.

gen_opi(op)

must generate the binary integer operation op on the two top entries of the stack which are guaranted to contain integer types. The result value should be put on the stack.

gen_opf(op)

same as gen_opi() for floating point operations. The two top entries of the stack are guaranted to contain floating point values of same types.

gen_cvt_itof()

integer to floating point conversion.

gen_cvt_ftoi()

floating point to integer conversion.

gen_cvt_ftof()

floating point to floating point of different size conversion.

gen_bounded_ptr_add()

gen_bounded_ptr_deref()

are only used for bounds checking.

8.8 Optimizations done

Constant propagation is done for all operations. Multiplications and divisions are optimized to shifts when appropriate. Comparison operators are optimized by maintaining a special cache for the processor flags. &&, || and ! are optimized by maintaining a special 'jump target' value. No other jump optimization is currently performed because it would require to store the code in a more abstract fashion.

Concept Index

Jump to: _ - a - b - c - d - e - f - g - i - j - l - m - o - p - q - r - s - t - u - v - w

_

· __asm__

a

· align directive

· aligned attribute

· ascii directive

· asciz directive

· assembler

· assembler directives

· assembly, inline

b

· bound checks

· bss directive

· byte directive

c

· caching processor flags

· cdecl attribute

· code generation

· comparison operators

· constant propagation

· CPU dependent

d

· data directive

· directives, assembler

· dllexport attribute

e

· ELF

f

· FILE, linker command

· fill directive

· flags, caching

g

· gas

· global directive

· globl directive

· GROUP, linker command

i

· inline assembly

· int directive

j

· jump optimization

l

· linker

· linker scripts

· long directive

m

· memory checks

o

· optimizations

· org directive

· OUTPUT_FORMAT, linker command

p

· packed attribute

· PE-i386

· previous directive

q

· quad directive

r

· regparm attribute

s

· scripts, linker

· section attribute

· section directive

· short directive

· skip directive

· space directive

· stdcall attribute

· strength reduction

· string directive

t

· TARGET, linker command

· text directive

u

· unused attribute

v

· value stack

· value stack, introduction

w

· word directive

This document was generated on 21 May 2009 using texi2html 1.56k.


1

1. Introduction

TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C compilers, it is meant to be self-relying: you do not need an external assembler or linker because TCC does that for you.

TCC compiles so fast that even for big projects Makefiles may not be necessary.

TCC not only supports ANSI C, but also most of the new ISO C99 standard and many GNUC extensions including inline assembly.

TCC can also be used to make C scripts, i.e. pieces of C source that you run as a Perl or Python script. Compilation is so fast that your script will be as fast as if it was an executable.

TCC can also automatically generate memory and bound checks (see section 6. TinyCC Memory and Bound checks) while allowing all C pointers operations. TCC can do these checks even if non patched libraries are used.

With libtcc, you can use TCC as a backend for dynamic code generation (see section 7. The libtcc library).

TCC mainly supports the i386 target on Linux and Windows. There are alpha ports for the ARM (arm-tcc) and the TMS320C67xx targets (c67-tcc). More information about the ARM port is available at http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html.

For usage on Windows, see also tcc-win32.txt.


2

2. Command line invocation

2.1 Quick start

usage: tcc [options] [infile1 infile2...] [`-run' infile args...]

TCC options are a very much like gcc options. The main difference is that TCC can also execute directly the resulting program and give it runtime arguments.

Here are some examples to understand the logic:

`tcc -run a.c'

Compile `a.c' and execute it directly

`tcc -run a.c arg1'

Compile a.c and execute it directly. arg1 is given as first argument to the main() of a.c.

`tcc a.c -run b.c arg1'

Compile `a.c' and `b.c', link them together and execute them. arg1 is given as first argument to the main() of the resulting program.

`tcc -o myprog a.c b.c'

Compile `a.c' and `b.c', link them and generate the executable `myprog'.

`tcc -o myprog a.o b.o'

link `a.o' and `b.o' together and generate the executable `myprog'.

`tcc -c a.c'

Compile `a.c' and generate object file `a.o'.

`tcc -c asmfile.S'

Preprocess with C preprocess and assemble `asmfile.S' and generate object file `asmfile.o'.

`tcc -c asmfile.s'

Assemble (but not preprocess) `asmfile.s' and generate object file `asmfile.o'.

`tcc -r -o ab.o a.c b.c'

Compile `a.c' and `b.c', link them together and generate the object file `ab.o'.

Scripting:

TCC can be invoked from scripts, just as shell scripts. You just need to add #!/usr/local/bin/tcc -run at the start of your C source:

#!/usr/local/bin/tcc -run
#include <stdio.h>

int main()
{
    printf("Hello World\n");
    return 0;
}

TCC can read C source code from standard input when `-' is used in place of `infile'. Example:

echo 'main(){puts("hello");}' | tcc -run -

2.2 Option summary

General Options:

`-v'

Display current TCC version, increase verbosity.

`-c'

Generate an object file (`-o' option must also be given).

`-o outfile'

Put object file, executable, or dll into output file `outfile'.

`-Bdir'

Set the path where the tcc internal libraries can be found (default is `PREFIX/lib/tcc').

`-bench'

Output compilation statistics.

`-run source [args...]'

Compile file source and run it with the command line arguments args. In order to be able to give more than one argument to a script, several TCC options can be given after the `-run' option, separated by spaces. Example:

tcc "-run -L/usr/X11R6/lib -lX11" ex4.c

In a script, it gives the following header:

#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>
int main(int argc, char **argv)
{
    ...
}

Preprocessor options:

`-Idir'

Specify an additional include path. Include paths are searched in the order they are specified. System include paths are always searched after. The default system include paths are: `/usr/local/include', `/usr/include' and `PREFIX/lib/tcc/include'. (`PREFIX' is usually `/usr' or `/usr/local').

`-Dsym[=val]'

Define preprocessor symbol `sym' to val. If val is not present, its value is `1'. Function-like macros can also be defined: `-DF(a)=a+1'

`-Usym'

Undefine preprocessor symbol `sym'.

Compilation flags:

Note: each of the following warning options has a negative form beginning with `-fno-'.

`-funsigned-char'

Let the char type be unsigned.

`-fsigned-char'

Let the char type be signed.

`-fno-common'

Do not generate common symbols for uninitialized data.

`-fleading-underscore'

Add a leading underscore at the beginning of each C symbol.

Warning options:

`-w'

Disable all warnings.

Note: each of the following warning options has a negative form beginning with `-Wno-'.

`-Wimplicit-function-declaration'

Warn about implicit function declaration.

`-Wunsupported'

Warn about unsupported GCC features that are ignored by TCC.

`-Wwrite-strings'

Make string constants be of type const char * instead of char *.

`-Werror'

Abort compilation if warnings are issued.

`-Wall'

Activate all warnings, except `-Werror', `-Wunusupported' and `-Wwrite-strings'.

Linker options:

`-Ldir'

Specify an additional static library path for the `-l' option. The default library paths are `/usr/local/lib', `/usr/lib' and `/lib'.

`-lxxx'

Link your program with dynamic library libxxx.so or static library libxxx.a. The library is searched in the paths specified by the `-L' option.

`-shared'

Generate a shared library instead of an executable (`-o' option must also be given).

`-static'

Generate a statically linked executable (default is a shared linked executable) (`-o' option must also be given).

`-rdynamic'

Export global symbols to the dynamic linker. It is useful when a library opened with dlopen() needs to access executable symbols.

`-r'

Generate an object file combining all input files (`-o' option must also be given).

`-Wl,-Ttext,address'

Set the start of the .text section to address.

`-Wl,--oformat,fmt'

Use fmt as output format. The supported output formats are:

elf32-i386

ELF output format (default)

binary

Binary image (only for executable output)

coff

COFF output format (only for executable output for TMS320C67xx target)

Debugger options:

`-g'

Generate run time debug information so that you get clear run time error messages: test.c:68: in function 'test5()': dereferencing invalid pointer instead of the laconic Segmentation fault.

`-b'

Generate additional support code to check memory allocations and array/pointer bounds. `-g' is implied. Note that the generated code is slower and bigger in this case.

`-bt N'

Display N callers in stack traces. This is useful with `-g' or `-b'.

Note: GCC options `-Ox', `-fx' and `-mx' are ignored.


3

3. C language support

3.1 ANSI C

TCC implements all the ANSI C standard, including structure bit fields and floating point numbers (long double, double, and float fully supported).

3.2 ISOC99 extensions

TCC implements many features of the new C standard: ISO C99. Currently missing items are: complex and imaginary numbers and variable length arrays.

Currently implemented ISOC99 features:

  • 64 bit long long types are fully supported.
  • The boolean type _Bool is supported.
  • __func__ is a string variable containing the current function name.
  • Variadic macros: __VA_ARGS__ can be used for function-like macros:
·
·                    #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__)

dprintf can then be used with a variable number of parameters.

  • Declarations can appear anywhere in a block (as in C++).
  • Array and struct/union elements can be initialized in any order by using designators:
·
·                    struct { int x, y; } st[10] = { [0].x = 1, [0].y = 2 };
·
·                    int tab[10] = { 1, 2, [5] = 5, [9] = 9};
  • Compound initializers are supported:
·
·                    int *p = (int []){ 1, 2, 3 };

to initialize a pointer pointing to an initialized array. The same works for structures and strings.

  • Hexadecimal floating point constants are supported:
·
·                          double d = 0x1234p10;

is the same as writing

          double d = 4771840.0;
  • inline keyword is ignored.
  • restrict keyword is ignored.

3.3 GNU C extensions

TCC implements some GNU C extensions:

  • array designators can be used without '=':
·
·                    int a[10] = { [0] 1, [5] 2, 3, 4 };
  • Structure field designators can be a label:
·
·                    struct { int x, y; } st = { x: 1, y: 1};

instead of

    struct { int x, y; } st = { .x = 1, .y = 1};
  • \e is ASCII character 27.
  • case ranges : ranges can be used in cases:
·
·                    switch(a) {
·                    case 1 ... 9:
·                          printf("range 1 to 9\n");
·                          break;
·                    default:
·                          printf("unexpected\n");
·                          break;
·                    }
  • The keyword __attribute__ is handled to specify variable or function attributes. The following attributes are supported:
    • aligned(n): align a variable or a structure field to n bytes (must be a power of two).
    • packed: force alignment of a variable or a structure field to 1.
    • section(name): generate function or data in assembly section name (name is a string containing the section name) instead of the default section.
    • unused: specify that the variable or the function is unused.
    • cdecl: use standard C calling convention (default).
    • stdcall: use Pascal-like calling convention.
    • regparm(n): use fast i386 calling convention. n must be between 1 and 3. The first n function parameters are respectively put in registers %eax, %edx and %ecx.
    • dllexport: export function from dll/executable (win32 only)

Here are some examples:

    int a __attribute__ ((aligned(8), section(".mysection")));

align variable a to 8 bytes and put it in section .mysection.

    int my_add(int a, int b) __attribute__ ((section(".mycodesection")))
    {
        return a + b;
    }

generate function my_add in section .mycodesection.

  • GNU style variadic macros:
·
·                    #define dprintf(fmt, args...) printf(fmt, ## args)
·
·                    dprintf("no arg\n");
·                    dprintf("one arg %d\n", 1);
  • __FUNCTION__ is interpreted as C99 __func__ (so it has not exactly the same semantics as string literal GNUC where it is a string literal).
  • The __alignof__ keyword can be used as sizeof to get the alignment of a type or an expression.
  • The typeof(x) returns the type of x. x is an expression or a type.
  • Computed gotos: &&label returns a pointer of type void * on the goto label label. goto *expr can be used to jump on the pointer resulting from expr.
  • Inline assembly with asm instruction:
·
·                static inline void * my_memcpy(void * to, const void * from, size_t n)
·                {
·                int d0, d1, d2;
·                __asm__ __volatile__(
·                        "rep ; movsl\n\t"
·                        "testb $2,%b4\n\t"
·                        "je 1f\n\t"
·                        "movsw\n"
·                        "1:\ttestb $1,%b4\n\t"
·                        "je 2f\n\t"
·                        "movsb\n"
·                        "2:"
·                        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
·                        :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
·                        : "memory");
·                return (to);
·                }

TCC includes its own x86 inline assembler with a gas-like (GNU assembler) syntax. No intermediate files are generated. GCC 3.x named operands are supported.

  • __builtin_types_compatible_p() and __builtin_constant_p() are supported.
  • #pragma pack is supported for win32 compatibility.

3.4 TinyCC extensions

  • __TINYC__ is a predefined macro to 1 to indicate that you use TCC.
  • #! at the start of a line is ignored to allow scripting.
  • Binary digits can be entered (0b101 instead of 5).
  • __BOUNDS_CHECKING_ON is defined if bound checking is activated.


4

4. TinyCC Assembler

Since version 0.9.16, TinyCC integrates its own assembler. TinyCC assembler supports a gas-like syntax (GNU assembler). You can desactivate assembler support if you want a smaller TinyCC executable (the C compiler does not rely on the assembler).

TinyCC Assembler is used to handle files with `.S' (C preprocessed assembler) and `.s' extensions. It is also used to handle the GNU inline assembler with the asm keyword.

4.1 Syntax

TinyCC Assembler supports most of the gas syntax. The tokens are the same as C.

  • C and C++ comments are supported.
  • Identifiers are the same as C, so you cannot use '.' or '$'.
  • Only 32 bit integer numbers are supported.

4.2 Expressions

  • Integers in decimal, octal and hexa are supported.
  • Unary operators: +, -, ~.
  • Binary operators in decreasing priority order:
    1. *, /, %
    2. &, |, ^
    3. +, -
  • A value is either an absolute number or a label plus an offset. All operators accept absolute values except '+' and '-'. '+' or '-' can be used to add an offset to a label. '-' supports two labels only if they are the same or if they are both defined and in the same section.

4.3 Labels

  • All labels are considered as local, except undefined ones.
  • Numeric labels can be used as local gas-like labels. They can be defined several times in the same source. Use 'b' (backward) or 'f' (forward) as suffix to reference them:
·
·                 1:
·                      jmp 1b /* jump to '1' label before */
·                      jmp 1f /* jump to '1' label after */
·                 1:

4.4 Directives

All directives are preceeded by a '.'. The following directives are supported:

  • .align n[,value]
  • .skip n[,value]
  • .space n[,value]
  • .byte value1[,...]
  • .word value1[,...]
  • .short value1[,...]
  • .int value1[,...]
  • .long value1[,...]
  • .quad immediate_value1[,...]
  • .globl symbol
  • .global symbol
  • .section section
  • .text
  • .data
  • .bss
  • .fill repeat[,size[,value]]
  • .org n
  • .previous
  • .string string[,...]
  • .asciz string[,...]
  • .ascii string[,...]

4.5 X86 Assembler

All X86 opcodes are supported. Only ATT syntax is supported (source then destination operand order). If no size suffix is given, TinyCC tries to guess it from the operand sizes.

Currently, MMX opcodes are supported but not SSE ones.


5

5. TinyCC Linker

5.1 ELF file generation

TCC can directly output relocatable ELF files (object files), executable ELF files and dynamic ELF libraries without relying on an external linker.

Dynamic ELF libraries can be output but the C compiler does not generate position independent code (PIC). It means that the dynamic library code generated by TCC cannot be factorized among processes yet.

TCC linker eliminates unreferenced object code in libraries. A single pass is done on the object and library list, so the order in which object files and libraries are specified is important (same constraint as GNU ld). No grouping options (`--start-group' and `--end-group') are supported.

5.2 ELF file loader

TCC can load ELF object files, archives (.a files) and dynamic libraries (.so).

5.3 PE-i386 file generation

TCC for Windows supports the native Win32 executable file format (PE-i386). It generates EXE files (console and gui) and DLL files.

For usage on Windows, see also tcc-win32.txt.

5.4 GNU Linker Scripts

Because on many Linux systems some dynamic libraries (such as `/usr/lib/libc.so') are in fact GNU ld link scripts (horrible!), the TCC linker also supports a subset of GNU ld scripts.

The GROUP and FILE commands are supported. OUTPUT_FORMAT and TARGET are ignored.

Example from `/usr/lib/libc.so':

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )


6

6. TinyCC Memory and Bound checks

This feature is activated with the `-b' (see section 2. Command line invocation).

Note that pointer size is unchanged and that code generated with bound checks is fully compatible with unchecked code. When a pointer comes from unchecked code, it is assumed to be valid. Even very obscure C code with casts should work correctly.

For more information about the ideas behind this method, see http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html.

Here are some examples of caught errors:

Invalid range with standard string function:

{
    char tab[10];
    memset(tab, 0, 11);
}

Out of bounds-error in global or local arrays:

{
    int tab[10];
    for(i=0;i<11;i++) {
        sum += tab[i];
    }
}

Out of bounds-error in malloc'ed data:

{
    int *tab;
    tab = malloc(20 * sizeof(int));
    for(i=0;i<21;i++) {
        sum += tab4[i];
    }
    free(tab);
}

Access of freed memory:

{
    int *tab;
    tab = malloc(20 * sizeof(int));
    free(tab);
    for(i=0;i<20;i++) {
        sum += tab4[i];
    }
}

Double free:

{
    int *tab;
    tab = malloc(20 * sizeof(int));
    free(tab);
    free(tab);
}


7

7. The libtcc library

The libtcc library enables you to use TCC as a backend for dynamic code generation.

Read the `libtcc.h' to have an overview of the API. Read `libtcc_test.c' to have a very simple example.

The idea consists in giving a C string containing the program you want to compile directly to libtcc. Then you can access to any global symbol (function or variable) defined.


8

8. Developer's guide

This chapter gives some hints to understand how TCC works. You can skip it if you do not intend to modify the TCC code.

8.1 File reading

The BufferedFile structure contains the context needed to read a file, including the current line number. tcc_open() opens a new file and tcc_close() closes it. inp() returns the next character.

8.2 Lexer

next() reads the next token in the current file. next_nomacro() reads the next token without macro expansion.

tok contains the current token (see TOK_xxx) constants. Identifiers and keywords are also keywords. tokc contains additional infos about the token (for example a constant value if number or string token).

8.3 Parser

The parser is hardcoded (yacc is not necessary). It does only one pass, except:

  • For initialized arrays with unknown size, a first pass is done to count the number of elements.
  • For architectures where arguments are evaluated in reverse order, a first pass is done to reverse the argument order.

8.4 Types

The types are stored in a single 'int' variable. It was choosen in the first stages of development when tcc was much simpler. Now, it may not be the best solution.

#define VT_INT        0  /* integer type */
#define VT_BYTE       1  /* signed byte type */
#define VT_SHORT      2  /* short type */
#define VT_VOID       3  /* void type */
#define VT_PTR        4  /* pointer */
#define VT_ENUM       5  /* enum definition */
#define VT_FUNC       6  /* function type */
#define VT_STRUCT     7  /* struct/union definition */
#define VT_FLOAT      8  /* IEEE float */
#define VT_DOUBLE     9  /* IEEE double */
#define VT_LDOUBLE   10  /* IEEE long double */
#define VT_BOOL      11  /* ISOC99 boolean type */
#define VT_LLONG     12  /* 64 bit integer */
#define VT_LONG      13  /* long integer (NEVER USED as type, only
                            during parsing) */
#define VT_BTYPE      0x000f /* mask for basic type */
#define VT_UNSIGNED   0x0010  /* unsigned type */
#define VT_ARRAY      0x0020  /* array type (also has VT_PTR) */
#define VT_BITFIELD   0x0040  /* bitfield modifier */

#define VT_STRUCT_SHIFT 16   /* structure/enum name shift (16 bits left) */

When a reference to another type is needed (for pointers, functions and structures), the 32 - VT_STRUCT_SHIFT high order bits are used to store an identifier reference.

The VT_UNSIGNED flag can be set for chars, shorts, ints and long longs.

Arrays are considered as pointers VT_PTR with the flag VT_ARRAY set.

The VT_BITFIELD flag can be set for chars, shorts, ints and long longs. If it is set, then the bitfield position is stored from bits VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11.

VT_LONG is never used except during parsing.

During parsing, the storage of an object is also stored in the type integer:

#define VT_EXTERN  0x00000080  /* extern definition */
#define VT_STATIC  0x00000100  /* static variable */
#define VT_TYPEDEF 0x00000200  /* typedef definition */

8.5 Symbols

All symbols are stored in hashed symbol stacks. Each symbol stack contains Sym structures.

Sym.v contains the symbol name (remember an idenfier is also a token, so a string is never necessary to store it). Sym.t gives the type of the symbol. Sym.r is usually the register in which the corresponding variable is stored. Sym.c is usually a constant associated to the symbol.

Four main symbol stacks are defined:

define_stack

for the macros (#defines).

global_stack

for the global variables, functions and types.

local_stack

for the local variables, functions and types.

global_label_stack

for the local labels (for goto).

label_stack

for GCC block local labels (see the __label__ keyword).

sym_push() is used to add a new symbol in the local symbol stack. If no local symbol stack is active, it is added in the global symbol stack.

sym_pop(st,b) pops symbols from the symbol stack st until the symbol b is on the top of stack. If b is NULL, the stack is emptied.

sym_find(v) return the symbol associated to the identifier v. The local stack is searched first from top to bottom, then the global stack.

8.6 Sections

The generated code and datas are written in sections. The structure Section contains all the necessary information for a given section. new_section() creates a new section. ELF file semantics is assumed for each section.

The following sections are predefined:

text_section

is the section containing the generated code. ind contains the current position in the code section.

data_section

contains initialized data

bss_section

contains uninitialized data

bounds_section

lbounds_section

are used when bound checking is activated

stab_section

stabstr_section

are used when debugging is actived to store debug information

symtab_section

strtab_section

contain the exported symbols (currently only used for debugging).

8.7 Code generation

8.7.1 Introduction

The TCC code generator directly generates linked binary code in one pass. It is rather unusual these days (see gcc for example which generates text assembly), but it can be very fast and surprisingly little complicated.

The TCC code generator is register based. Optimization is only done at the expression level. No intermediate representation of expression is kept except the current values stored in the value stack.

On x86, three temporary registers are used. When more registers are needed, one register is spilled into a new temporary variable on the stack.

8.7.2 The value stack

When an expression is parsed, its value is pushed on the value stack (vstack). The top of the value stack is vtop. Each value stack entry is the structure SValue.

SValue.t is the type. SValue.r indicates how the value is currently stored in the generated code. It is usually a CPU register index (REG_xxx constants), but additional values and flags are defined:

#define VT_CONST     0x00f0
#define VT_LLOCAL    0x00f1
#define VT_LOCAL     0x00f2
#define VT_CMP       0x00f3
#define VT_JMP       0x00f4
#define VT_JMPI      0x00f5
#define VT_LVAL      0x0100
#define VT_SYM       0x0200
#define VT_MUSTCAST  0x0400
#define VT_MUSTBOUND 0x0800
#define VT_BOUNDED   0x8000
#define VT_LVAL_BYTE     0x1000
#define VT_LVAL_SHORT    0x2000
#define VT_LVAL_UNSIGNED 0x4000
#define VT_LVAL_TYPE     (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)

VT_CONST

indicates that the value is a constant. It is stored in the union SValue.c, depending on its type.

VT_LOCAL

indicates a local variable pointer at offset SValue.c.i in the stack.

VT_CMP

indicates that the value is actually stored in the CPU flags (i.e. the value is the consequence of a test). The value is either 0 or 1. The actual CPU flags used is indicated in SValue.c.i. If any code is generated which destroys the CPU flags, this value MUST be put in a normal register.

VT_JMP

VT_JMPI

indicates that the value is the consequence of a conditional jump. For VT_JMP, it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted. These values are used to compile the || and && logical operators. If any code is generated, this value MUST be put in a normal register. Otherwise, the generated code won't be executed if the jump is taken.

VT_LVAL

is a flag indicating that the value is actually an lvalue (left value of an assignment). It means that the value stored is actually a pointer to the wanted value. Understanding the use VT_LVAL is very important if you want to understand how TCC works.

VT_LVAL_BYTE

VT_LVAL_SHORT

VT_LVAL_UNSIGNED

if the lvalue has an integer type, then these flags give its real type. The type alone is not enough in case of cast optimisations.

VT_LLOCAL

is a saved lvalue on the stack. VT_LLOCAL should be eliminated ASAP because its semantics are rather complicated.

VT_MUSTCAST

indicates that a cast to the value type must be performed if the value is used (lazy casting).

VT_SYM

indicates that the symbol SValue.sym must be added to the constant.

VT_MUSTBOUND

VT_BOUNDED

are only used for optional bound checking.

8.7.3 Manipulating the value stack

vsetc() and vset() pushes a new value on the value stack. If the previous vtop was stored in a very unsafe place(for example in the CPU flags), then some code is generated to put the previous vtop in a safe storage.

vpop() pops vtop. In some cases, it also generates cleanup code (for example if stacked floating point registers are used as on x86).

The gv(rc) function generates code to evaluate vtop (the top value of the stack) into registers. rc selects in which register class the value should be put. gv() is the most important function of the code generator.

gv2() is the same as gv() but for the top two stack entries.

8.7.4 CPU dependent code generation

See the `i386-gen.c' file to have an example.

load()

must generate the code needed to load a stack value into a register.

store()

must generate the code needed to store a register into a stack value lvalue.

gfunc_start()

gfunc_param()

gfunc_call()

should generate a function call

gfunc_prolog()

gfunc_epilog()

should generate a function prolog/epilog.

gen_opi(op)

must generate the binary integer operation op on the two top entries of the stack which are guaranted to contain integer types. The result value should be put on the stack.

gen_opf(op)

same as gen_opi() for floating point operations. The two top entries of the stack are guaranted to contain floating point values of same types.

gen_cvt_itof()

integer to floating point conversion.

gen_cvt_ftoi()

floating point to integer conversion.

gen_cvt_ftof()

floating point to floating point of different size conversion.

gen_bounded_ptr_add()

gen_bounded_ptr_deref()

are only used for bounds checking.

8.8 Optimizations done

Constant propagation is done for all operations. Multiplications and divisions are optimized to shifts when appropriate. Comparison operators are optimized by maintaining a special cache for the processor flags. &&, || and ! are optimized by maintaining a special 'jump target' value. No other jump optimization is currently performed because it would require to store the code in a more abstract fashion.


TCC

  • Retour au Grimoire

  • Introduction

  • 1er programme

  • ligne de commande

  • Windows Ressources

  • image GDI

  • Win32API &
    utiliser une DLL

  • Python26.dll
    (utiliser une DLL)

  • Créer une DLL
    (ammap.dll)

  • Téléchargements

  • tccinpy
    TCC in PYthon

Vu dans ... http://mclaveau.com/grimoire/tcc.htm

TCC - Tiny C Compiler est un compilateur C extrêmement petit (moins de 1 Mo), mais très rapide en compilation (plus d'un million de lignes par seconde).
TCC est simpliste, mais a le gros avantage de permettre une programmation directe. Pas d'installation, il suffit de copier un dossier. Pour écrire un programme, un éditeur de texte suffit, et la mise en route est immédiate, pour une programmation quasi-instantanée. Pas de projet à définir, pas de dépendances, pas de foisonnement d'outils variés et différents, pas d'atomisation du code-source.

Historique. Au départ, Fabrice Bellard a créé OTCC pour concourir à l'IOCCC (http://fr.wikipedia.org/wiki/International_Obfuscated_C_Code_Contest), qu'il a gagné en 2002.
Il a ensuite "dé-obsfucated" OTCC, ce qui a donné TCC.

Quelques liens :

  • http://fr.wikipedia.org/wiki/Tiny_C_Compiler

  • http://bellard.org/tcc

  • http://lists.gnu.org/archive/html/tinycc-devel

  • http://repo.or.cz/w/tinycc.git (pour les utilisateurs de Git)

Mon intérêt à TCC est très limité, car je ne connais pas le langage C. J'en sais juste assez pour comprendre ce que j'ai fait. Mais, cela a un avantage : ce ne sont que des trucs simples.

Le but de cette page sur TCC est de retransmettre les quelques trouvailles que j'ai faites avec TCC sous Windows, afin d'éviter à d'autres de perdre du temps en investigations pas troujours très faciles. Des façons de faire, pour créer des DLL ou utiliser des ressources Windows, ne sont pas toujours simples à trouver.

Les exemples sont bruts, presque sans commentaires, mais assez simples à comprendre pour être utilisables par tout programmeur qui connait un minimum Windows.

1er programme - comment compiler

Voici le code-source (fichier p1.c) :

#include <stdio.h>

void main() {
    printf("Bonjour, Monde !\n");
}

Pour le compiler, utiliser cette commande :

tcc -o p1.exe p1.c

Vous obtiendrez le fichier p1.exe, parfaitement exécutable.
Voilà, vous avez créé votre premier programme avec TCC.

Ligne de commande - retrouver les arguments

Voici le code-source (fichier p2.c) :

#include <stdio.h>

void main(int argc,
                char*argv[]) {
int i;
printf("Nb: %d\n",argc);
for(i=0 ; i<argc ; i++){
printf("Arg.num.%d
                : %s \n", i, argv[i]);
}
}

Le compiler avec cette commande :

tcc -o p2.exe p2.c

Lancer ensuite p2.exe aaa 123 "ABC ZZZ" ; vous devriez voir les paramètres récupérés par le programme.

Windows

Notre première fenêtre sous Windows (fichier p3.c) :

#include <windows.h>

const char g_szClassName[] = "maclasswin";

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
   switch(msg)
   {
       case WM_CLOSE:
           MessageBox(NULL,"Demande de fermeture de la fenêtre.","Message Windows",MB_ICONEXCLAMATION | MB_OK);
           DestroyWindow(hwnd);
           break;

       case WM_DESTROY:
           PostQuitMessage(0);
           break;

       default:
           return DefWindowProc(hwnd, msg, wParam, lParam);
           break;  //à cause de certains antivirus...
   }
   return 0;
}

int WINAPI WinMain(HINSTANCE
                hInstance, HINSTANCE hPrevInstance, LPSTR
                lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

   wc.cbSize =
                sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL,
                IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL,
                IDC_ARROW);
wc.hbrBackground =
                (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = NULL;
wc.lpszClassName = g_szClassName;
wc.hIconSm = LoadIcon(NULL,
                IDI_APPLICATION);
if(!RegisterClassEx(&wc)) {
MessageBox(NULL,
                "Pb d'enregistrement de la fenêtre",
                "Erreur", MB_ICONEXCLAMATION | MB_OK);
return 0;
}

   hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
       g_szClassName,
       "Ma première fenêtre",   //titre
       WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT,
       320,  //largeur
       200,  //hauteur
       NULL, NULL, hInstance, NULL);

   if(hwnd == NULL)
                {
MessageBox(NULL, "Pb de création de la
                fenêtre", "Erreur",
                MB_ICONEXCLAMATION | MB_OK);
return 0;
}

   ShowWindow(hwnd, nCmdShow);
   UpdateWindow(hwnd);

   while(GetMessage(&Msg, NULL, 0, 0) > 0) {
       TranslateMessage(&Msg);
       DispatchMessage(&Msg);
   }

   return Msg.wParam;
}

Compiler avec cette commande :

tcc -o p3.exe p3.c

Alors, non seulement ce programme crée une fenêtre, mais il intercepte aussi la fermeture de la fenêtre (un message est affiché).

Ressources

Je n'ai jamais apprécié l'histoire des ressources, avec des fichiers séparés. Cela se traduit par une atomisation des code-sources, et une multiplicité des traitements péri-compilation (compilation de ressources, éditeur de liens, intégration des ressources à l'exécutable, etc.).
De plus TCC s'intègre très mal avec les éditeurs et compilateurs de ressources classiques, comme ceux de Microsoft ou de Borland.

Heureusement, il existe une possibilité, que nous allons mettre en oeuvre dans un exemple. Il s'agit d'utiliser le compilateur de ressources de MinGW. Pour cela, il faut récupérer, dans une installation MinGW, les programmes (fichiers) suivants :

    • cc1.exe

    • gcc.exe

    • windres.exe

Nous allons définir (utiliser) les ressources suivantes :

  • Un icone, fichier "ponx.ico", qui DOIT être présent dans le dossier en cours.

  • Un menu, organisé comme ça :
    Fichier
    Terminer
    Divers
    Aller
    Aller ailleurs (ligne grisée)
    3ème ligne

L'ensemble des codes-source est composé de trois fichiers :  p4.h  p4.rc  p4.c :

(fichier p4.h) Il contient les constantes identifiant les éléments des ressources :

#define ID_MONICON 201
#define ID_MONMENU 101
#define ID_TERMINER 9001
#define ID_ALLER 9002
#define ID_3 9003

(fichier p4.rc) Il contient la définition des ressources :

#include "p4.h"

ID_MONMENU MENU
BEGIN
    POPUP "&Fichier"
    BEGIN
        MENUITEM "&Terminer", ID_TERMINER
    END

    POPUP "&Divers"
    BEGIN
        MENUITEM "&Aller", ID_ALLER
        MENUITEM "A&ller ailleurs", 0, GRAYED
        MENUITEM "3ème ligne", ID_3
    END
END

ID_MONICON ICON "ponx.ico"

Le fichier source en langage C (fichier p4.c) :

#include <windows.h>
#include "p4.h"

const char g_szClassName[] = "maClasseWin";

HBITMAP g_hbmBall = NULL;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg) {
        case WM_COMMAND:
            switch(LOWORD(wParam)) {
                case ID_TERMINER:
                MessageBox(hwnd, "la ligne de menu  'Terminer'", "Vous avez sélectionné", MB_OK | MB_ICONINFORMATION);
                DestroyWindow(hwnd);
                break;

                case ID_ALLER:
                MessageBox(hwnd, "la ligne de menu  'Aller'", "Vous avez sélectionné", MB_OK | MB_ICONINFORMATION);
                break;

                case ID_3:
                MessageBox(hwnd, "la ligne de menu  '3ème ligne'", "Vous avez sélectionné", MB_OK | MB_ICONINFORMATION);
                break;
            }
        break;

        case WM_LBUTTONDOWN: {
            char szFileName[MAX_PATH];
            HINSTANCE hInstance = GetModuleHandle(NULL);

                GetModuleFileName(hInstance, szFileName,
                MAX_PATH);
MessageBox(hwnd, szFileName, "Clic gauche
                dans :", MB_OK | MB_ICONINFORMATION);
}
break;

        case WM_RBUTTONDOWN: {
            char szFileName[MAX_PATH];
            HINSTANCE hInstance = GetModuleHandle(NULL);

                GetModuleFileName(hInstance, szFileName,
                MAX_PATH);
MessageBox(hwnd, szFileName, "Clic droit
                dans :", MB_OK | MB_ICONINFORMATION);
}
break;

        case WM_CLOSE:
            DestroyWindow(hwnd);
        break;

        case WM_DESTROY:
         DeleteObject(g_hbmBall);
            PostQuitMessage(0);
        break;

        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
        break;
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE
                hInstance, HINSTANCE hPrevInstance, LPSTR
                lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_MONICON));
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = MAKEINTRESOURCE(ID_MONMENU);
    wc.lpszClassName = g_szClassName;
    wc.hIconSm       = (HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(ID_MONICON), IMAGE_ICON, 16, 16, 0);
    if(!RegisterClassEx(&wc)) {
        MessageBox(NULL, "Pb d'enregistrement de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        g_szClassName,
        "Fenêtre avec un icône et un menu (voir aussi les clics droit et gauche)",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        600,   //largeur
        280,   //hauteur
        NULL, NULL, hInstance, NULL
        );
    if(hwnd == NULL) {
        MessageBox(NULL, "Pb de création de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&Msg, NULL, 0, 0) > 0) {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

Avant de compiler, il faut traiter les ressources. Pour cela, nous allons utiliser la commande :

windres.exe -O coff p4.rc -o p4.o

La compilation elle-même :

tcc p4.c p4.o -o p4.exe

Le programme p4.exe ouvre une fenêtre, avec l'icone associé (qui est maintenant intégré dans le fichier exécutable), et avec le menu prévu.
Lorsqu'un utilisateur va sélectionner (cliquer) sur une entrée du menu, l'action sera interceptée, et un message affiché.
En supplément gratuit, le programme va aussi intercepter les clics gauches et droits sur la fenêtre. Ceci ne concerne pas les ressources, mais rend l'exemple plus attractif ;-)

Image & GDI

Cet exemple ouvre une fenêtre, charge une image, à partir d'un fichier au format .BMP, et affiche trois textes, de tailles, couleurs et emplacements différents.

Voici le code-source (fichier p5.c) :

#include <windows.h>

const char g_szClassName[] =
                "maClasseWin";
HBITMAP g_hBMP = NULL;
char *pWindowText;

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    switch(msg) {

        case WM_CREATE:
            g_hBMP = (HBITMAP)LoadImage(NULL,
                                       "tintin.bmp",     // nom du fichier
                                       IMAGE_BITMAP,     // type = bitmap
                                       0, 0,             // 0,0 = taille d'origine
                                       LR_LOADFROMFILE);

            if(g_hBMP == NULL)
                MessageBox(hwnd, "Pb pour lire tintin.bmp", "Erreur", MB_OK | MB_ICONEXCLAMATION);
            break;

        case WM_PAINT: {
            PAINTSTRUCT pst;
            RECT        rct;
            HDC hdc = BeginPaint(hwnd, &pst);

                BITMAP bm;
HDC hdcMem = CreateCompatibleDC(hdc);
HBITMAP hOld = SelectObject(hdcMem, g_hBMP);
GetObject(g_hBMP, sizeof(bm), &bm);
BitBlt(hdc, 100, 100, bm.bmWidth, bm.bmHeight,
                hdcMem, 0, 0, SRCCOPY);
SelectObject(hdcMem, hOld);
DeleteDC(hdcMem);

                //le 36, c'est la taille de la police
HFONT hFont = CreateFont (36, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, TEXT ("Arial"));
hFont = (HFONT) SelectObject (hdc, hFont);
GetClientRect(hwnd, &rct);
SetTextColor(hdc, RGB(0,0,0));
SetBkColor(hdc, RGB(255,255,255));  //
                TRANSPARENT);  //OPAQUE
//TextOut  écrit en X,Y
char *texte = "Attention !";
TextOut(hdc, 315, 145, texte, strlen(texte));
char *texte = "TCC est";
TextOut(hdc, 330, 190, texte, strlen(texte));
char *texte = "super !";
TextOut(hdc, 345, 230, texte, strlen(texte));

                char *texte = "AAAA éè €€ Hello,
                Monde !";
//le 24, c'est la taille de la police
hFont = CreateFont (24, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, TEXT ("Arial"));
hFont = (HFONT) SelectObject (hdc, hFont);
SetTextColor(hdc, RGB(0,20,120));
SetBkColor(hdc, RGB(200,244,244));
//DrawText écrit à patir du début de la
                fenêtre
DrawText(hdc, texte, -1, &rct, 0);
                //DT_WORDBREAK
                DT_CENTER|DT_SINGLELINE|DT_VCENTER);

                HFONT hFont = CreateFont (24, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, TEXT ("Arial"));
hFont = (HFONT) SelectObject (hdc, hFont);
GetClientRect(hwnd, &rct);
SetTextColor(hdc, RGB(180,0,20));
SetBkColor(hdc, RGB(255,200,255));  //
                TRANSPARENT);  //OPAQUE
char *texte = "  {Echap} pour
                quitter  ";
TextOut(hdc, 190, 50, texte, strlen(texte));

            EndPaint(hwnd, &pst);
        }
        break;

                case WM_KEYDOWN:
switch(wParam) {
case VK_ESCAPE:
MessageBox(hwnd, "On quitte",
                "Echap", MB_OK | MB_ICONINFORMATION);
DestroyWindow(hwnd);
break;
}
break;

        case WM_CLOSE:
            DestroyWindow(hwnd);
            break;

        case WM_DESTROY:
         DeleteObject(g_hBMP);
            PostQuitMessage(0);
            break;

        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
            break;
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE
                hInstance, HINSTANCE hPrevInstance, LPSTR
                lpCmdLine, int nCmdShow) {
WNDCLASSEX wc;
HWND hwnd;
MSG Msg;

                wc.cbSize
                = sizeof(WNDCLASSEX);
wc.style
                = 0;
wc.lpfnWndProc   =
                WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon
                = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor       =
                LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground =
                (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName  = NULL;
wc.lpszClassName =
                g_szClassName;
wc.hIconSm       =
                LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc))
                {
MessageBox(NULL, "Pb d'enregistrement de la
                fenêtre", "Erreur",
                MB_ICONEXCLAMATION | MB_OK);
return 0;
}

    hwnd = CreateWindowEx(WS_EX_CLIENTEDGE,
       g_szClassName,
       "Fenêtre avec image (bmp) et textes.",   //titre
       WS_OVERLAPPEDWINDOW,
       CW_USEDEFAULT, CW_USEDEFAULT,
       640,  //largeur
       580,  //hauteur
       NULL, NULL, hInstance, NULL);
    if(hwnd == NULL) {
       MessageBox(NULL, "Pb de création de la fenêtre", "Erreur", MB_ICONEXCLAMATION | MB_OK);
       return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&Msg, NULL, 0, 0) > 0) {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

Pour le compiler, utiliser la commande :

tcc -o p5.exe p5.c

Attention, le fichier tintin.bmp DOIT être présent dans le dossier courant.

Win32API - Utiliser les API de Windows

Si de nombreuses fonctions des API de Windows sont définies en standard (dans Windows.h), certaines font partie de Shell32.DLL (ou d'autres DLL). Et, pour pouvoir utiliser (les fonctions de) cette DLL, il faut se servir de l'outil tiny_impdef.exe. Il permet d'extraire les définitions des fonctions publiques d'une DLL, dans un fichier .def

On l'utilise de cette façon : tiny_impdef.exe C:\Windows\System32\shell32.dll
le fichier shell32.def est alors créé (c'est un simple fichier texte). Nous l'utiliserons lors de la compilation.

L'exemple ci-dessous effectue la séquence de traitements suivante :

  • Lance le bloc-notes

  • Attend 2 secondes

  • Lance la calculatrice

  • Attend 2 secondes

  • Met le bloc-notes au premier-plan

  • Déplace la fenêtre (et change la taille)

  • Déplace la fenêtre (et change la taille)

  • Cache la fenêtre du bloc-notes

  • Ré-affiche la fenêtre du bloc-notes

  • Change le titre de la fenêtre

  • Simule quelques touches du clavier, dans le bloc-notes

  • Ouvre le menu "Fichier"

  • Envoie "Q" (Quitter)

  • Envoie "R" (ne pas enRegistrer)

  • Déplace la calculatrice

  • Déplace la calculatrice

  • Ferme la calculatrice

Voici le code-source (fichier p6.c) :

#include <windows.h>
#include <stdio.h>

void t(char tch) {
 keybd_event((CHAR)(SHORT)VkKeyScan(tch), 0, 0, 0);
}

void tcode(int cod) {
 keybd_event((CHAR)(SHORT)cod, 0, 0, 0);
}

void ts(char tch) {  //touche avec shift
 keybd_event( 0x10, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
 keybd_event((CHAR)(SHORT)VkKeyScan(tch), 0, 0, 0);
 keybd_event( 0x10, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

void tc(char tch) {  //touche avec ctrl
 keybd_event( 0x11, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
 keybd_event((CHAR)(SHORT)VkKeyScan(tch), 0, 0, 0);
 keybd_event( 0x11, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

void ta(char tch) {  //touche avec alt
 keybd_event( 0xA4, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
 keybd_event((CHAR)(SHORT)VkKeyScan(tch), 0, 0, 0);
 keybd_event( 0xA4, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

void tacode(int cod) {  //code-touche avec alt
 keybd_event( 0xA4, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
 keybd_event((CHAR)(SHORT)cod, 0, 0, 0);
 keybd_event( 0xA4, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

    // on lance NotePad
    // la méthode ci-dessous fonctionne, mais pas très bien.
    // int rh = (int) ShellExecuteA(0,"open","notepad.exe","","
 system("start \"\" C:\\Windows\\notepad.exe");
    Sleep(2000);  // on attend deux secondes

    //int rh = (int) ShellExecuteA(0,"open","calc.exe","","",SW_SHOWDEFAULT);
 system("start \"\" C:\\Windows\\system32\\calc.exe");
    Sleep(2000);  // on attend deux secondes

 HWND hc = FindWindow("Notepad",NULL);

 //ShowWindow(hc,SW_SHOWNORMAL);
 SetForegroundWindow(hc);
 Sleep(250);
 MoveWindow(hc, 120, 120, 800, 500, FALSE);
 Sleep(1000);
 MoveWindow(hc, 20, 20, 600, 300, FALSE);
 Sleep(100);

 char *texte;
texte="Titre modifié";
SetWindowText(hc, texte);  //on change
                le titre de la fenêtre

    Sleep(1000);
    SetFocus(hc);
    Sleep(250);
    ShowWindow( hc, SW_HIDE);
    ShowWindow( hc, SW_HIDE);
    Sleep(1000);
    ShowWindow( hc, SW_SHOW);
    Sleep(500);

 t('a'); t('b'); t('c');
                t('d'); t('e');
t('a'); t('b'); t('c'); t('d'); t('e');
t('a'); t('b'); t('c'); t('d'); t('e');
tc('m');  // {Ctrl}{M} équivaut à
                {Entrée} et à 0x0D

 t('a'); t('b'); t('c');
                t('d'); t('e');
t('a'); t('b'); t('c'); t('d'); t('e');
t('a'); t('b'); t('c'); t('d'); t('e');
tcode(0x0D);  // {Entrée}

 t('x'); t('y'); t('z');

 tcode(0x09); // {TAB}
 ts('e');  // Shift => E majuscule
 ts('e'); ts('e'); ts('e'); ts('e');

                Sleep(2000);
ta('F');   //
                {Alt}{F}
Sleep(800);
t('q');
Sleep(1000);
t('r');

    Sleep(500);
HWND hc =
                FindWindow("CalcFrame",NULL);
RECT r;
GetWindowRect(hc, &r);
MoveWindow(hc, 400, 200, r.right-r.left,
                r.bottom-r.top, TRUE);
Sleep(1000);
GetWindowRect(hc, &r);
MoveWindow(hc, 20, 20, r.right-r.left,
                r.bottom-r.top, TRUE);
Sleep(500);
PostMessage(hc, WM_CLOSE, 0,
                0);
Sleep(50);

 return 1;
}

Compilation avec cette commande :

tcc -o p6.exe p6.c shell32.def

Notez l'utilisation shell32.def pour rendre disponibles les fonctions de Shell32.dll
Détail, le fichier p6.exe, ne pèse que 4 ko.

Python26.dll - Python par utilisation d'une DLL

Utiliser Python depuis TCC est assez simple. Il suffit d'utiliser python26.dll. Pour cela, comme dans l'exemple précédent, on se sert de la commande :
tiny_impdef.exe C:\Windows\System32\python26.dll

Le code-source (fichier p7.c) est assez simple :

#include <stdio.h>

int main(int argc, char*argv[]) {
  Py_Initialize();

  PyRun_SimpleString("f=open('bbb.txt','w')\n
f.write('111111\\r\\n222222')\n
f.close()");

  PyRun_SimpleString("import ctypes\n
ctypes.windll.user32.MessageBoxW(0, u'par Python + ctypes', u'Message affiché ', 0)\n");

  Py_Finalize();
  return 0;
}

On compile avec la commande :

tcc -o p7.exe p7.c python26.def

À l'exécution, le fichier p7.exe, va faire deux choses (deux petits scripts en Python) :

  • créer un fichier texte, bbb.txt contenant 111111\n222222

  • Afficher un petit message, via ctypes

Notez aussi l'utilisation de scripts Python multi-lignes.

Créer une DLL - ammap.dll

La DLL que nous allons créer dans cet exemple est utile (ce n'est pas seulement un exemple). Elle offre un accès, en lecture et écriture à deux mmap.
Rappel : les mmap sont des fichiers mappés en mémoire, accessibles depuis plusieurs processus simultanément, sans aucun contrôle ou verrou. Les fonctions mmap existent en standard dans de nombreux langages (non MS), comme Python, Ruby, Perl, Haskell, etc. et sont très utiles pour faire de l' IPC (Inter-Processus-Communication, ou échange de données entre différents processus).

Voici le code-source (fichier p8.c) :

#include <windows.h>
#include <memory.h>
#include <string.h>

#define DLL_EXPORT __declspec(dllexport)

#define SHMEMSIZE 32767

static LPVOID lpvMem = NULL;      // pointeur pour mémoire partagée
static HANDLE hMapObject = NULL;  // handle pour mmap

static LPVOID lpvMem2 = NULL;
static HANDLE hMapObject2 = NULL;

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {

   BOOL fInit, fIgnore;

   switch (fdwReason) {
    // chargement de la DLL
    case DLL_PROCESS_ATTACH:
     break;
    // attachement d'un processus
    case DLL_THREAD_ATTACH:
     break;
    // détachement d'un processus
    case DLL_THREAD_DETACH:
     break;
    // déchargement de la DLL
    case DLL_PROCESS_DETACH:
     // unmap la mémoire partagée et ferme le mmap1
     fIgnore = UnmapViewOfFile(lpvMem);
     fIgnore = CloseHandle(hMapObject);

     //
                unmap la mémoire partagée et ferme le mmap2
fIgnore =
                UnmapViewOfFile(lpvMem2);
fIgnore =
                CloseHandle(hMapObject2);
break;
default:
break;
}
return TRUE;
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpvReserved);
}

// ------ 1 ----------------------------------------------------------------------

// Ouverture du mmap
DLL_EXPORT VOID __stdcall Open(char *nom) {

   BOOL fInit;

 // Create a named file mapping object
 hMapObject = CreateFileMapping(
  INVALID_HANDLE_VALUE,   // handle null
  NULL,                   // attributs de sécurité
  PAGE_READWRITE,         // accès read/write
  0,                      // taille: high 32-bits
  SHMEMSIZE,              // taille: low 32-bits
  nom      // nom de l'objet mappé
 );
 if (hMapObject == NULL)
  return;

 // est-ce que le mmap
                existe déjà ?
fInit = (GetLastError() !=
                ERROR_ALREADY_EXISTS);
// obtient le pointeur sur le mmap
lpvMem = MapViewOfFile(
hMapObject,
                // handle
FILE_MAP_WRITE, // accès read/write
0,
                // taille: high 32-bits
0,
                // taille: low 32-bits
0
                // default: map entire file
);
if(lpvMem == NULL) return; // si ERREUR
                ERREUR ERREUR ERREUR
// si le mmap n'existait pas déjà, on
                initialise la mémoire
if(fInit) {
memset(lpvMem, '\0', SHMEMSIZE);
return;
}
return;
}

// Fermeture du mmap
DLL_EXPORT VOID __stdcall Close(){
   BOOL fInit, fIgnore;
   fIgnore = UnmapViewOfFile(lpvMem);
   // ferme le mmap
   fIgnore = CloseHandle(hMapObject);
}

// Ecriture dans le mmap
DLL_EXPORT VOID __stdcall SetSharedMem(char *str)
                {
char *lpszTmp;
lpszTmp = (char *) lpvMem;
strncpy(lpszTmp,str,SHMEMSIZE);
}

// Lecture dans le mmap
DLL_EXPORT VOID __stdcall GetSharedMem(char *str,
                int size) {
char *lpszTmp;
lpszTmp = (char *) lpvMem;
strncpy(str,lpszTmp,size);
}

// ------ 2 ----------------------------------------------------------------------

DLL_EXPORT VOID __stdcall Open2(char *nom) {
    BOOL fInit;

 hMapObject2 = CreateFileMapping(
  INVALID_HANDLE_VALUE,
  NULL,
  PAGE_READWRITE,
  0,
  SHMEMSIZE,
  nom
 );
 if (hMapObject2 == NULL)
  return;

 fInit = (GetLastError() != ERROR_ALREADY_EXISTS);
 lpvMem2 = MapViewOfFile(
  hMapObject2,
  FILE_MAP_WRITE,
  0,
  0,
  0
 );
 if(lpvMem2 == NULL) return; // si ERREUR ERREUR ERREUR ERREUR
 if(fInit) {
  memset(lpvMem2, '\0', SHMEMSIZE);
  return;
 }
 return;
}

DLL_EXPORT VOID __stdcall
                Close2() {
BOOL fInit, fIgnore;
fIgnore = UnmapViewOfFile(lpvMem2);
fIgnore = CloseHandle(hMapObject2);
}

DLL_EXPORT VOID __stdcall
                SetSharedMem2(char *str) {
char *lpszTmp;
lpszTmp = (char *) lpvMem2;
strncpy(lpszTmp,str,SHMEMSIZE);
}

DLL_EXPORT VOID __stdcall
                GetSharedMem2(char *str, int size) {
char *lpszTmp;
lpszTmp = (char *) lpvMem2;
strncpy(str,lpszTmp,size);
}

Pour le compiler, et créer la DLL, on utilisera cette commande :

tcc -shared -o p8.dll p8.c

Notez que, en plus du fichier p8.dll, il y a création d'un fichier P8.def.

Téléchargements

Pour éviter aux lecteurs de chercher (longuement) sur le Net, je vous propose quelques téléchargements dans cette page :

  • TCC pour Windows, sur le site de TCC :
    http://download.savannah.nongnu.org/releases/tinycc/tcc-0.9.25-win32-bin.zip

  • Les fichiers-sources-exemples de cette page (compressés en un ZIP) : exsources.zip

  • Les outils du compilateur de ressources de MinGW (compressés en un ZIP) : rescompil.zip

  • Un exemple de dossier TCC prêt à l'emploi (décompresser dans C:\tcc) : tcc.zip

C'est tout !


Téléchargement et cours pour les compilateurs Turbo C et Turbo C++ | Toutla.com

Aller au contenu principal

Toutla.com

Cherchez plus, il y a tout là !

Menu principal

  • Accueil
  • Logiciels
  • Graphisme
  • Jouez !!!
  • Programmation
  • Annuaire
  • Contact

Téléchargement et cours pour les compilateurs Turbo C et Turbo C++

Note : Turbo C et Turbo C++ ont été développés par l'éditeur de logiciel borland au début des années 90. De nombreuses versions du langage C et C++ ont apparu depuis, il est donc conseillé d'utiliser des logiciels plus récents pour débuter (par exemple la suite Visual Studio Express disponible dans la rubrique Logiciel > Programmation). Cependant, cette page est conservée car Turbo C et Turbo C++ sont toujours utilisés dans certaines universités et dans un but d'initiation.

Le logiciel

Turbo C (versions 2.01 ou 3.0) est à la fois un environnement de développement permettant d'écrire des programme en C, mais également un compilateur produisant et exécutant les applications. Turbo C++ (version 1.01, 2.0 ou 3.0) est un compilateur pour le langage C++. Nous allons étudier en détail l'utilisation de ces logiciels dans ce tutorial. Nous nous intéresserons particulièrement à Turbo C, mais Turbo C++ est très semblable et vous n'aurez aucun mal à suivre le tutoriel sur celui-ci.

Turbo C et Turbo C++ sont compatibles avec la plupart des versions de Windows, dont Windows XP, Windows Vista et Windows 7 (seven).

Pour programmer en C ou en C++, un compilateur est indispensable : c'est un logiciel qui va se charger de transformer les lignes de code tapées par le programmeur (vous) en un format compréhensible par votre ordinateur. Il vous suffira finalement de lancer cette application pour voir le résultat des lignes de code que vous avez tapées précédemment. Le développement d'une application se décompose donc en trois étapes bien distinctes :

  • Ecrire son programme en ligne de code
  • Compiler le code pour le transformer en application
  • Exécuter l'application

Toutes ces étapes sont réalisables au sein du même logiciel : Turbo C ou Turbo C++. Idéal pour débuter, gratuit, il fonctionne sous la majorité des systèmes d'exploitations Windows.

Télécharger Turbo C

Télécharger Turbo C++

Une fois téléchargé, vous devez l'installer. Commencez d'abord par le décompresser dans le répertoire de votre choix, puis suivez la procédure d'installation classique. Pour exécuter Turbo C, il ne vous reste qu'à aller dans le répertoire C:\TC puis de double-cliquer sur TC. Une fois exécuté, appuyez sur une touche pour faire disparaître l'écran d'accueil. Vous vous retrouvez donc face à une interface ... très portée sur le bleu.

A savoir : vous pouvez passer du mode plein écran au mode fenêtre en pressant simultanément les touches "ALT" + "Enter" de votre clavier.

Les menus

Vous voyez en haut de l'application différents menus : File, Edit, Run, Compile, Project, Options, Debug, Break/Watch. Vous pouvez atteindre les sous-menus en pressant simultanément "ALT" et la première lettre du menu. Pour revenir à l'écran principal, il suffira de taper "ESC". Nous allons maintenant énumérer les différents menus et sous-menus les plus utilisés.

File

File regroupe toutes les actions utiles pour la gestion des fichiers :

  • Load : Permet de charger un fichier .c précédemment enregistré.
  • New : Charge un nouveau fichier vide.
  • Save : Enregistre le fichier en cours.
  • Write to : Permet de déplacer le fichier en cours.
  • Directory : Sélectionne un fichier situé sur un autre dossier que le dossier courant.
  • Change Dir : Change le dossier courant.
  • Quit : Quitte Turbo C.

Edit

Edit permet simplement de retourner à l'éditeur.

Run

Run propose des outils qui concernent l'exécution du programme :

  • Run : Permet d'exécuter le programme en cours.
  • User Screen : Affiche l'écran vu par l'utilisateur.

Compile

Compile concerne, comme son nom l'indique, les options du compilateur :

  • Make EXE File : Créé un fichier EXE, vous n'aurez alors plus besoin de turbo C pour l'exécuter. Mais attention, ce n'est pas si facile que cela comme nous le verrons plus loin.
  • Get Info : Affiche certaines informations importantes à l'écran, comme la taille actuelle du fichier ou encore la mémoire disponible.

Project

Project n'est pas très utile, tout du moins au début. Seule une commande peut nous intéresser :

  • Break Make On : Correspond au niveau à partir duquel le compilateur doit arrêter le programme. Vous avez le choix entre "Warning", qui correspond à de simples avertissements, "Error" qui est le niveau recommandé, "Fatal Error" qui correspond aux erreurs pouvant altérer le système et enfin "Link" qui sont des erreurs liées à l'éditeur de liens. Il n'est pas conseillé de modifier cette option dans un premier temps.

Options

Affiche les options concernant Turbo C. Il n'y a pas de raison de les modifier pour le moment, voilà tout de même leurs fonctions.

  • Compiler : Affiche les options du compilateur.
  • Linker : Affiche les options de l'éditeur de liens.
  • Environment : Si vous désirez avoir plus de lignes visibles, appuyez sur "Enter", puis allez sur Screen Size. Pressez à nouveau "Enter" et sélectionnez "43/50 line display". Mais attention, le code sera plus difficilement lisible.

Les autres options ne nous intéressent pas pour le moment :

  • Directories : Permet de changer les dossiers des bibliothèques et autres ressources nécessaires au bon fonctionnement de Turbo C. Si il a été installé sans problème, il n'y a pas de raison de modifier ces dossiers.
  • Arguments : Utilisé pour entrer des arguments automatiquement au démarrage de Turbo C.
  • Save Options : Sauve les options modifiées.
  • Retrieve Options : Charge des options précédemment sauvées.

Debug et Break/Watch

Debug et Break/Watch ne sont pas utiles pour débuter sous Turbo C.

Les barres d'outils

Maintenant que vous connaissez tout ce qu'il faut savoir des menus, intéressons-nous à la barre d'outils, c'est à dire la barre grise située en bas de l'écran et qui comporte plusieurs actions : Help, Zoom, Switch, Trace, Step, Make et Menu. Cette barre est en fait double, car d'autre actions sont disponibles. Pour y accéder, laissez la touche "ALT" appuyée, ce qui a pour effet l'accès aux actions : Last Help, Pick, Swap, Prev/Next Error et Comp. Voici les principales actions détaillées dans les deux chapitres suivants.

La barre d'outil principale

Elle donne accès aux opérations les plus utilisées :

  • Help : affiche l'aide, un chapitre lui est consacré plus loin dans ce cours.
  • Zoom : permet d'enlever le cadre autour de la zone d'édition.
  • Switch : permet de passer du mode édition au mode débogueur. Cette option sera expliquée plus en détail dans un prochain chapitre.
  • Make : permet de compiler et de créer le programme sans l'exécuter.
  • Menu : cette option renvoie au menu.

La barre d'outil ALT

Cette barre est accessible en laissant la touche "ALT" appuyée.

  • Last help : Affiche la dernière aide affichée, un chapitre est consacré à l'aide plus loin dans ce cours.
  • Swap : Charge un fichier.

L'éditeur

Voyons maintenant l'éditeur. Certaines informations sont disponibles rapidement vers le haut de l'écran, en gris, juste en dessous de la barre de menu. Tout d'abord les chiffres derrière "line" et "col" donne le numéro de la ligne et le numéro de la colonne du curseur.

Maintenant appuyez plusieurs fois sur la touche "Inser" (ou "Ins") de votre clavier. Vous devriez voir le mot "Insert" clignoter au niveau de la barre d'édition. Cela vous indique si vous êtes en mode Insertion ou non. Si vous n'êtes pas en mode Insertion, chaque caractère remplace celui qui le suit. En mode Insertion chaque caractère vient s'intercaler entre celui qui le précède et celui qui le suit (ces deux modes sont couramment utilisées dans les traitements de texte actuels).

Tout à droite de cette barre d'édition figure le nom du fichier, avec l'extension .c, précédé du répertoire dans lequel il se situe. Si vous ne l'avez pas encore enregistré, il s'affiche par défaut C:NONAME.C. Juste avant ce nom, si vous voyez un astérisque (*),c'est que le fichier en cours a été modifié depuis le dernier enregistrement.

Un premier programme

On va maintenant créer un programme pour mieux tester les options de Turbo C. Même si vous ne savez pas encore programmer en C, vous pourrez comprendre celui-là. Vous allez donc taper les lignes suivantes :

main()
{
   clrscr();
   printf("hello world");
}

Voici la description du programme : main() suivi de l'accolade est obligatoire pour commencer un programme en C, clrscr(); donne l'ordre d'effacer l'écran, printf("hello world"); permet d'écrire "hello world" sur l'écran et } est obligatoire à la fin du programme.

On va maintenant exécuter notre petit programme. Pour cela on va taper simultanément sur "CTRL" + "F9". On voit alors un panneau s'afficher un court instant puis plus rien. Pourquoi ? En fait Turbo C a bien exécuté notre programme, puis est revenu sur l'écran d'édition. Comment savoir si tout s'est bien passé ? Il suffit d'afficher l'écran utilisateur. Pour cela, tapez simultanément sur "ALT" + "F5". Vous voyez alors à l'écran le texte "hello world". Parfait.

Pour revenir à l'écran d'édition, tapez n'importe quelle touche.

Les erreurs

Turbo C est non seulement un éditeur et un compilateur, mais il vous permet aussi de détecter plus facilement vos erreurs. Prenons un exemple : il faut savoir que le ";" est obligatoire à la fin de chaque ligne d’instruction. On va donc l'enlever après le clrscr() pour tester le débogueur. Le nouveau programme est :

main()
{
   clrscr()
   printf("hello world");
}

On va maintenant essayer d'exécuter ce programme. Pressez donc "CTRL" + F9. Il vient une fenêtre où il est affiché sur fond bleu : "Errors : Press any key".

Tapez alors n'importe quelle touche, là une ligne de l'éditeur se grise. La fenêtre "Message" en bas indique entre autre : "statement missing ; in function main". En français : "Il manque le ; dans la fonction main". C'est alors la ligne située juste au dessus de celle grisée qui contient l'erreur. Il est maintenant beaucoup plus facile de la corriger (surtout dans des programmes de plusieurs centaines ou milliers de lignes). Pressez maintenant "Enter" et vous reviendrez alors sur l'éditeur.

L'aide

L'aide est très utile sous Turbo C. Pour voir concrètement ce qu'elle peut vous apporter, commençons par écrire le même programme bogué que précédemment :

main()
{
   clrscr()
   printf("hello world");
}

Tentez de l'exécuter en tapant "CTRL" + "F9", la fenêtre d'erreur apparaît, tapez alors "Enter". Si vous voulez en savoir plus sur "statement missing ; in function main" qui est écrit dans la partie message, pressez la touche "F1" ce qui a pour effet de développer l'erreur. Ici la fenêtre indique "The compiler encountered an expression statement without a semicolon following it". En français : "Le compilateur a rencontré une instruction non-suivie d'un point-virgule"

On peut aussi obtenir de l'aide en pressant à n'importe quel moment deux fois la touche F1. Là c'est un menu qui apparaît. Les plus utiles sont encore les sous-menus "Header Files" et "KeyWords". Dans "header Files" vous obtiendrez toutes les informations sur les fonctions des bibliothèques (vous verrez dans le cours sur la programmation l'utilité de ces bibliothèques). Avec "KeyWords" vous avez la syntaxe des éléments propres au langage C. Sachez aussi que vous pouvez descendre ou monter dans l'aide grâce au touche "UP" et "DOWN".

Les blocs

Il n'y a pas vraiment de fonction couper/copier/coller dans Turbo C. Si vous désirez dupliquer une partie du code dans le même fichier, vous devez manier des blocs. Reprenons à nouveau le programme précédent :

main()
{
   clrscr();
   printf("hello world");
}

Essayons maintenant de dupliquer les deux lignes de code. Nous allons les insérer dans un bloc. Tout d'abord, placez votre curseur au début de "clrscr();" puis pressez simultanément "CTRL" + "K", relâchez les touches puis pressez B. Nous avons alors créé le début du bloc. Maintenant, placez vous à la fin de la ligne "print("hello world");" puis pressez "CTRL" + "K" suivi de "K". Vous avez alors le bloc qui s'est grisé. Pour dupliquer ce bloc, placez-vous où vous voulez puis pressez "CTRL" + "K" suivi de "C". Si vous désirez couper/coller un bloc, pressez "CTRL" + "K" suivi de "V".

Toutes ces instructions sont expliquées dans l'aide. Pour l'obtenir : "F1", "F1", "flèche droite", trois fois "flèche gauche" pour sélectionner "Blocks Command" puis pressez "Enter". Vous avez alors accès à toutes les commandes possibles pour les blocs. N'oubliez pas que vous pouvez descendre ou monter dans l'aide grâce au touche "UP" et "DOWN".

Ce cours est maintenant terminé. Si vous avez des remarques, des critiques ou des questions, utilisez la page de contact !

Espace:

  • Programmation

Programmation:

  • C

Programmation

  • Cours sur le HTML
  • Balises XHTML
  • Cours de PHP / MySQL
  • Initiation à Turbo C
  • Visual Basic 6.0
  • Calculatrice TI

Annonces

Graphisme

  • Thème
    • Téléchargement
  • Curseurs
    • Téléchargement
    • Installation
    • Création
  • Icônes
    • Téléchargement
    • Installation
    • Création
  • GIFs animés
    • Création
  • Paint - tutoriel

Logiciels

  • Applis mobile
  • Bureautique
  • Internet
  • Jeux
  • Multimédia
  • Programmation

Annuaire de sites

  • Graphisme
  • Insolite
  • Jeux vidéo
  • Programmation

Toutla.com Copyright 2011.

Nous veillons aux respects des droits d'auteur : si par erreur un contenu protégé
est disponible sans indication sur ce site, merci de contacter l'administrateur,
il sera retiré ou mis à jour dans les plus brefs délais.


OTCC : Obfuscated Tiny C Compiler

Obfuscated Tiny C Compiler

What is it ?

The Obfuscated Tiny C Compiler (OTCC) is a very small C compiler I wrote in order to win the International Obfuscated C Code Contest (IOCCC) in 2002.

My goal was to write the smallest C compiler which is able to compile itself. I choose a subset of C which was general enough to write a small C compiler. Then I extended the C subset until I reached the maximum size authorized by the contest: 2048 bytes of C source excluding the ';', '{', '}' and space characters.

I choose to generate i386 code. The original OTCC code could only run on i386 Linux because it relied on endianness and unaligned access. It generated the program in memory and launched it directly. External symbols were resolved with dlsym().

In order to have a portable version of OTCC, I made a variant called OTCCELF. It is only a little larger than OTCC, but it generates directly a dynamically linked i386 ELF executable from a C source without relying on any binutils tools! OTCCELF was tested succesfully on i386 Linux and on Sparc Solaris.

NOTE: My other project TinyCC which is a fully featured ISOC99 C compiler was written by starting from the source code of OTCC !

Download

  • Original OTCC version (runs only on i386 Linux): otcc.c (link it with -ldl).
  • OTCC with i386 ELF output (should be portable): otccelf.c.
  • Example of C program that can be compiled: otccex.c.
  • [New] The non-obfuscated versions are finally available: otccn.c and otccelfn.c. These non-obfuscated versions do not self compile. They are provided for documentation purpose.
Compilation:
gcc -O2 otcc.c -o otcc -ldl
gcc -O2 otccelf.c -o otccelf
Self-compilation:
./otccelf otccelf.c otccelf1
As a test, here are the executables generated by OTCCELF: otcc1, otccelf1, otccex1.

C Subset Definition

Read joint example otccex.c to have an example of C program.
  • Expressions:
    • binary operators, by decreasing priority order: '*' '/' '%', '+' '-', '>>' '<<', '<' '<=' '>' '>=', '==' '!=', '&', '^', '|', '=', '&&', '||'.
    • '&&' and '||' have the same semantics as C : left to right evaluation and early exit.
    • Parenthesis are supported.
    • Unary operators: '&', '*' (pointer indirection), '-' (negation), '+', '!', '~', post fixed '++' and '--'.
    • Pointer indirection ('*') only works with explicit cast to 'char *', 'int *' or 'int (*)()' (function pointer).
    • '++', '--', and unary '&' can only be used with variable lvalue (left value).
    • '=' can only be used with variable or '*' (pointer indirection) lvalue.
    • Function calls are supported with standard i386 calling convention. Function pointers are supported with explicit cast. Functions can be used before being declared.
  • Types: only signed integer ('int') variables and functions can be declared. Variables cannot be initialized in declarations. Only old K&R function declarations are parsed (implicit integer return value and no types on arguments).
  • Any function or variable from the libc can be used because OTCC uses the libc dynamic linker to resolve undefined symbols.
  • Instructions: blocks ('{' '}') are supported as in C. 'if' and 'else' can be used for tests. The 'while' and 'for' C constructs are supported for loops. 'break' can be used to exit loops. 'return' is used for the return value of a function.
  • Identifiers are parsed the same way as C. Local variables are handled, but there is no local name space (not a problem if different names are used for local and global variables).
  • Numbers can be entered in decimal, hexadecimal ('0x' or '0X' prefix), or octal ('0' prefix).
  • '#define' is supported without function like arguments. No macro recursion is tolerated. Other preprocessor directives are ignored.
  • C Strings and C character constants are supported. Only '\n', '\"', '\'' and '\\' escapes are recognized.
  • C Comments can be used (but no C++ comments).
  • No error is displayed if an incorrect program is given.
  • Memory: the code, data, and symbol sizes are limited to 100KB (it can be changed in the source code).

OTCC Invocation

You can use OTCC by typing:
otcc prog.c [args]...
or by giving the C source to its standard input. 'args' are given to the 'main' function of prog.c (argv[0] is prog.c).

Examples:

  • Sample compilation and execution:
    otcc otccex.c 10
  • Self compilation:
    otcc otcc.c otccex.c 10
  • Self compilation iterated...
    otcc otcc.c otcc.c otccex.c 10
An alternate syntax is to use it as a script interpreter: you can put
#!/usr/local/bin/otcc
at the beginning of your C source if you installed otcc at this place.

OTCCELF Invocation

You can use OTCCELF by typing:
otccelf prog.c prog
chmod 755 prog
'prog' is the name of the ELF file you want to generate.

Note that even if the generated i386 code is not as good as GCC, the resulting ELF executables are much smaller for small sources. Try this program:

#include <stdio.h>

main()
{
    printf("Hello World\n");
    return 0;
}
Results:
Compiler | Executable size (in bytes)
OTCCELF | 424
GCC (stripped) | 2448

Links

  • TinyCC, a tiny but complete C compiler.
  • Tiny ELF programs from Brian Raiter.
  • Linux assembly projects.

License

The obfuscated OTCC and OTCCELF are public domain. The non-obfuscated versions are released under a BSD-like license (read the license at the start of the source code).
This page is Copyright (c) 2002 Fabrice Bellard
Fabrice Bellard - http://bellard.org/- http://www.tinycc.org/


TCC : Tiny C Compiler

Tiny C Compiler

News

[Note: I am no longer working on TCC. Check the mailing list to get up to date information.]

(Feb 15, 2013) TCC version 0.9.26 is out thanks to Thomas Preud'homme (Changelog). Summary of the changes:

  • Support for C99 VLA
  • Generation of make dependencies (-MD/-MF)
  • Support improved for various architectures (x86-64, arm, OSX, WinCE, kFreeBSD, Hurd)
  • A bunch of bug fixes

(May 20, 2009) TCC version 0.9.25 is out thanks to Grischka (Changelog). TCC version 0.9.25 is the first that supports the x86-64 target. Thanks to Shinichiro Hamaji for this.

(Apr 1, 2008) TCC version 0.9.24 is out thanks to Grischka (Changelog). TCC now supports compilation from standard input and the arm eabi.

(Jun 17, 2005) TCC version 0.9.23 is out (Changelog). This is the first version with support for the Windows target.

(Nov 8, 2004) TCC version 0.9.22 is out (Changelog). Linux kernel compilation is 30% faster (10 seconds on a 2.4 GHz Pentium 4).

(Oct 25, 2004) TCC version 0.9.21 is out (Changelog). This version is the first one able to build a bootable Linux kernel with only a few patches to the kernel sources. As a demonstration, you can try the TCCBOOT boot loader. It is able to compile and boot a Linux kernel directly from its source code.

NOTE: if you want to compile the Linux kernel with TCC, you must use a custom build script as in TCCBOOT . I never tried to compile the Linux kernel with TinyCC and the standard Linux Makefiles.

Features

  • SMALL! You can compile and execute C code everywhere, for example on rescue disks (about 100KB for x86 TCC executable, including C preprocessor, C compiler, assembler and linker).
  • FAST! tcc generates x86 code. No byte code overhead. Compile, assemble and link several times faster than GCC.
  • UNLIMITED! Any C dynamic library can be used directly. TCC is heading torward full ISOC99 compliance. TCC can of course compile itself.
  • SAFE! tcc includes an optional memory and bound checker. Bound checked code can be mixed freely with standard code.
  • Compile and execute C source directly. No linking or assembly necessary. Full C preprocessor and GNU-like assembler included.
  • C script supported : just add '#!/usr/local/bin/tcc -run' at the first line of your C source, and execute it directly from the command line.
  • With libtcc, you can use TCC as a backend for dynamic code generation.

Download

Compilation Speed

Compilation speed for the Links Browser project. There are 76936 lines (including headers). 1950947 lines (67.2 MBytes) are compiled because the same headers are included in many files. TinyCC is about 9 times faster than GCC.

Compiler | Time(s) | lines/second | MBytes/second
TinyCC 0.9.22 | 2.27 | 859000 | 29.6
GCC 3.2 -O0 | 20.0 | 98000 | 3.4

Measures were done on a 2.4 GHz Pentium 4. Real time is measured. Compilation time includes compilation, assembly and linking.

More up to date tests are available: 1, 2, 3, 4.

Online Documentation

You want to help ?

Here are some suggestions:
  • Report bugs to the mailing list (and eventually fix them).

Links

  • TinyCC mailing list
  • Savannah project page and git repository
  • OTCC - The smallest self compiling pseudo C compiler
  • FFASN1 - My small but powerful ASN.1 compiler.
  • TinyCC fork by Rob Landley
  • LLVM Compiler Infrastructure
  • SmartEiffel - With TCC you can compile your Eiffel code faster
  • The GNU C Compiler
  • The LCC Compiler
  • The Small Device C Compiler
  • Cyclone, A Safe Dialect of C
  • The D language
  • Programming in C
  • The Scriptometer evaluates various scripting languages (including TCC).

License

TCC is distributed under the GNU Lesser General Public License.
anybrowser
Copyright (c) 2001-2009 Fabrice Bellard
Fabrice Bellard - http://bellard.org/- http://www.tinycc.org/


Tiny C Compiler Reference Documentation

Table of Contents

  • 1. Introduction
  • 2. Command line invocation
    • 2.1 Quick start
    • 2.2 Option summary
  • 3. C language support
    • 3.1 ANSI C
    • 3.2 ISOC99 extensions
    • 3.3 GNU C extensions
    • 3.4 TinyCC extensions
  • 4. TinyCC Assembler
    • 4.1 Syntax
    • 4.2 Expressions
    • 4.3 Labels
    • 4.4 Directives
    • 4.5 X86 Assembler
  • 5. TinyCC Linker
    • 5.1 ELF file generation
    • 5.2 ELF file loader
    • 5.3 PE-i386 file generation
    • 5.4 GNU Linker Scripts
  • 6. TinyCC Memory and Bound checks
  • 7. The libtcc library
  • 8. Developer's guide
    • 8.1 File reading
    • 8.2 Lexer
    • 8.3 Parser
    • 8.4 Types
    • 8.5 Symbols
    • 8.6 Sections
    • 8.7 Code generation
      • 8.7.1 Introduction
      • 8.7.2 The value stack
      • 8.7.3 Manipulating the value stack
      • 8.7.4 CPU dependent code generation
    • 8.8 Optimizations done
  • Concept Index

1. Introduction

TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C compilers, it is meant to be self-relying: you do not need an external assembler or linker because TCC does that for you.

TCC compiles so fast that even for big projects Makefiles may not be necessary.

TCC not only supports ANSI C, but also most of the new ISO C99 standard and many GNUC extensions including inline assembly.

TCC can also be used to make C scripts, i.e. pieces of C source that you run as a Perl or Python script. Compilation is so fast that your script will be as fast as if it was an executable.

TCC can also automatically generate memory and bound checks (see section 6. TinyCC Memory and Bound checks) while allowing all C pointers operations. TCC can do these checks even if non patched libraries are used.

With libtcc, you can use TCC as a backend for dynamic code generation (see section 7. The libtcc library).

TCC mainly supports the i386 target on Linux and Windows. There are alpha ports for the ARM (arm-tcc) and the TMS320C67xx targets (c67-tcc). More information about the ARM port is available at http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html.

For usage on Windows, see also tcc-win32.txt.

2. Command line invocation

2.1 Quick start

usage: tcc [options] [infile1 infile2...] [`-run' infile args...]

TCC options are a very much like gcc options. The main difference is that TCC can also execute directly the resulting program and give it runtime arguments.

Here are some examples to understand the logic:

`tcc -run a.c'
Compile `a.c' and execute it directly
`tcc -run a.c arg1'
Compile a.c and execute it directly. arg1 is given as first argument to the main() of a.c.
`tcc a.c -run b.c arg1'
Compile `a.c' and `b.c', link them together and execute them. arg1 is given as first argument to the main() of the resulting program.
`tcc -o myprog a.c b.c'
Compile `a.c' and `b.c', link them and generate the executable `myprog'.
`tcc -o myprog a.o b.o'
link `a.o' and `b.o' together and generate the executable `myprog'.
`tcc -c a.c'
Compile `a.c' and generate object file `a.o'.
`tcc -c asmfile.S'
Preprocess with C preprocess and assemble `asmfile.S' and generate object file `asmfile.o'.
`tcc -c asmfile.s'
Assemble (but not preprocess) `asmfile.s' and generate object file `asmfile.o'.
`tcc -r -o ab.o a.c b.c'
Compile `a.c' and `b.c', link them together and generate the object file `ab.o'.

Scripting:

TCC can be invoked from scripts, just as shell scripts. You just need to add #!/usr/local/bin/tcc -run at the start of your C source:

#!/usr/local/bin/tcc -run
#include <stdio.h>

int main()
{
    printf("Hello World\n");
    return 0;
}

TCC can read C source code from standard input when `-' is used in place of `infile'. Example:

echo 'main(){puts("hello");}' | tcc -run -

2.2 Option summary

General Options:

`-v'
Display current TCC version, increase verbosity.
`-c'
Generate an object file (`-o' option must also be given).
`-o outfile'
Put object file, executable, or dll into output file `outfile'.
`-Bdir'
Set the path where the tcc internal libraries can be found (default is `PREFIX/lib/tcc').
`-bench'
Output compilation statistics.
`-run source [args...]'
Compile file source and run it with the command line arguments args. In order to be able to give more than one argument to a script, several TCC options can be given after the `-run' option, separated by spaces. Example:
tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
In a script, it gives the following header:
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11
#include <stdlib.h>
int main(int argc, char **argv)
{
    ...
}

Preprocessor options:

`-Idir'
Specify an additional include path. Include paths are searched in the order they are specified. System include paths are always searched after. The default system include paths are: `/usr/local/include', `/usr/include' and `PREFIX/lib/tcc/include'. (`PREFIX' is usually `/usr' or `/usr/local').
`-Dsym[=val]'
Define preprocessor symbol `sym' to val. If val is not present, its value is `1'. Function-like macros can also be defined: `-DF(a)=a+1'
`-Usym'
Undefine preprocessor symbol `sym'.

Compilation flags:

Note: each of the following warning options has a negative form beginning with `-fno-'.

`-funsigned-char'
Let the char type be unsigned.
`-fsigned-char'
Let the char type be signed.
`-fno-common'
Do not generate common symbols for uninitialized data.
`-fleading-underscore'
Add a leading underscore at the beginning of each C symbol.

Warning options:

`-w'
Disable all warnings.

Note: each of the following warning options has a negative form beginning with `-Wno-'.

`-Wimplicit-function-declaration'
Warn about implicit function declaration.
`-Wunsupported'
Warn about unsupported GCC features that are ignored by TCC.
`-Wwrite-strings'
Make string constants be of type const char * instead of char *.
`-Werror'
Abort compilation if warnings are issued.
`-Wall'
Activate all warnings, except `-Werror', `-Wunusupported' and `-Wwrite-strings'.

Linker options:

`-Ldir'
Specify an additional static library path for the `-l' option. The default library paths are `/usr/local/lib', `/usr/lib' and `/lib'.
`-lxxx'
Link your program with dynamic library libxxx.so or static library libxxx.a. The library is searched in the paths specified by the `-L' option.
`-shared'
Generate a shared library instead of an executable (`-o' option must also be given).
`-static'
Generate a statically linked executable (default is a shared linked executable) (`-o' option must also be given).
`-rdynamic'
Export global symbols to the dynamic linker. It is useful when a library opened with dlopen() needs to access executable symbols.
`-r'
Generate an object file combining all input files (`-o' option must also be given).
`-Wl,-Ttext,address'
Set the start of the .text section to address.
`-Wl,--oformat,fmt'
Use fmt as output format. The supported output formats are:
elf32-i386
ELF output format (default)
binary
Binary image (only for executable output)
coff
COFF output format (only for executable output for TMS320C67xx target)

Debugger options:

`-g'
Generate run time debug information so that you get clear run time error messages: test.c:68: in function 'test5()': dereferencing invalid pointer instead of the laconic Segmentation fault.
`-b'
Generate additional support code to check memory allocations and array/pointer bounds. `-g' is implied. Note that the generated code is slower and bigger in this case.
`-bt N'
Display N callers in stack traces. This is useful with `-g' or `-b'.

Note: GCC options `-Ox', `-fx' and `-mx' are ignored.

3. C language support

3.1 ANSI C

TCC implements all the ANSI C standard, including structure bit fields and floating point numbers (long double, double, and float fully supported).

3.2 ISOC99 extensions

TCC implements many features of the new C standard: ISO C99. Currently missing items are: complex and imaginary numbers and variable length arrays.

Currently implemented ISOC99 features:

  • 64 bit long long types are fully supported.
  • The boolean type _Bool is supported.
  • __func__ is a string variable containing the current function name.
  • Variadic macros: __VA_ARGS__ can be used for function-like macros:
        #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__)
    dprintf can then be used with a variable number of parameters.
  • Declarations can appear anywhere in a block (as in C++).
  • Array and struct/union elements can be initialized in any order by using designators:
        struct { int x, y; } st[10] = { [0].x = 1, [0].y = 2 };

    int tab[10] = { 1, 2, [5] = 5, [9] = 9};
  • Compound initializers are supported:
        int *p = (int []){ 1, 2, 3 };
    to initialize a pointer pointing to an initialized array. The same works for structures and strings.
  • Hexadecimal floating point constants are supported:
              double d = 0x1234p10;
    is the same as writing
              double d = 4771840.0;
  • inline keyword is ignored.
  • restrict keyword is ignored.

3.3 GNU C extensions

TCC implements some GNU C extensions:

  • array designators can be used without '=':
        int a[10] = { [0] 1, [5] 2, 3, 4 };
  • Structure field designators can be a label:
        struct { int x, y; } st = { x: 1, y: 1};
    instead of
        struct { int x, y; } st = { .x = 1, .y = 1};
  • \e is ASCII character 27.
  • case ranges : ranges can be used in cases:
        switch(a) {
    case 1 ... 9:
          printf("range 1 to 9\n");
          break;
    default:
          printf("unexpected\n");
          break;
    }
  • The keyword __attribute__ is handled to specify variable or function attributes. The following attributes are supported:
    • aligned(n): align a variable or a structure field to n bytes (must be a power of two).
    • packed: force alignment of a variable or a structure field to 1.
    • section(name): generate function or data in assembly section name (name is a string containing the section name) instead of the default section.
    • unused: specify that the variable or the function is unused.
    • cdecl: use standard C calling convention (default).
    • stdcall: use Pascal-like calling convention.
    • regparm(n): use fast i386 calling convention. n must be between 1 and 3. The first n function parameters are respectively put in registers %eax, %edx and %ecx.
    • dllexport: export function from dll/executable (win32 only)
    Here are some examples:
        int a __attribute__ ((aligned(8), section(".mysection")));
    align variable a to 8 bytes and put it in section .mysection.
        int my_add(int a, int b) __attribute__ ((section(".mycodesection")))
    {
        return a + b;
    }
    generate function my_add in section .mycodesection.
  • GNU style variadic macros:
        #define dprintf(fmt, args...) printf(fmt, ## args)

    dprintf("no arg\n");
    dprintf("one arg %d\n", 1);
  • __FUNCTION__ is interpreted as C99 __func__ (so it has not exactly the same semantics as string literal GNUC where it is a string literal).
  • The __alignof__ keyword can be used as sizeof to get the alignment of a type or an expression.
  • The typeof(x) returns the type of x. x is an expression or a type.
  • Computed gotos: &&label returns a pointer of type void * on the goto label label. goto *expr can be used to jump on the pointer resulting from expr.
  • Inline assembly with asm instruction:
    static inline void * my_memcpy(void * to, const void * from, size_t n)
{
int d0, d1, d2;
__asm__ __volatile__(
        "rep ; movsl\n\t"
        "testb $2,%b4\n\t"
        "je 1f\n\t"
        "movsw\n"
        "1:\ttestb $1,%b4\n\t"
        "je 2f\n\t"
        "movsb\n"
        "2:"
        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
        :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
        : "memory");
return (to);
}
    TCC includes its own x86 inline assembler with a gas-like (GNU assembler) syntax. No intermediate files are generated. GCC 3.x named operands are supported.
  • __builtin_types_compatible_p() and __builtin_constant_p() are supported.
  • #pragma pack is supported for win32 compatibility.

3.4 TinyCC extensions

  • __TINYC__ is a predefined macro to 1 to indicate that you use TCC.
  • #! at the start of a line is ignored to allow scripting.
  • Binary digits can be entered (0b101 instead of 5).
  • __BOUNDS_CHECKING_ON is defined if bound checking is activated.

4. TinyCC Assembler

Since version 0.9.16, TinyCC integrates its own assembler. TinyCC assembler supports a gas-like syntax (GNU assembler). You can desactivate assembler support if you want a smaller TinyCC executable (the C compiler does not rely on the assembler).

TinyCC Assembler is used to handle files with `.S' (C preprocessed assembler) and `.s' extensions. It is also used to handle the GNU inline assembler with the asm keyword.

4.1 Syntax

TinyCC Assembler supports most of the gas syntax. The tokens are the same as C.

  • C and C++ comments are supported.
  • Identifiers are the same as C, so you cannot use '.' or '$'.
  • Only 32 bit integer numbers are supported.

4.2 Expressions

  • Integers in decimal, octal and hexa are supported.
  • Unary operators: +, -, ~.
  • Binary operators in decreasing priority order:
    1. *, /, %
    2. &, |, ^
    3. +, -
  • A value is either an absolute number or a label plus an offset. All operators accept absolute values except '+' and '-'. '+' or '-' can be used to add an offset to a label. '-' supports two labels only if they are the same or if they are both defined and in the same section.

4.3 Labels

  • All labels are considered as local, except undefined ones.
  • Numeric labels can be used as local gas-like labels. They can be defined several times in the same source. Use 'b' (backward) or 'f' (forward) as suffix to reference them:
     1:
      jmp 1b /* jump to '1' label before */
      jmp 1f /* jump to '1' label after */
 1:

4.4 Directives

All directives are preceeded by a '.'. The following directives are supported:

  • .align n[,value]
  • .skip n[,value]
  • .space n[,value]
  • .byte value1[,...]
  • .word value1[,...]
  • .short value1[,...]
  • .int value1[,...]
  • .long value1[,...]
  • .quad immediate_value1[,...]
  • .globl symbol
  • .global symbol
  • .section section
  • .text
  • .data
  • .bss
  • .fill repeat[,size[,value]]
  • .org n
  • .previous
  • .string string[,...]
  • .asciz string[,...]
  • .ascii string[,...]

4.5 X86 Assembler

All X86 opcodes are supported. Only ATT syntax is supported (source then destination operand order). If no size suffix is given, TinyCC tries to guess it from the operand sizes.

Currently, MMX opcodes are supported but not SSE ones.

5. TinyCC Linker

5.1 ELF file generation

TCC can directly output relocatable ELF files (object files), executable ELF files and dynamic ELF libraries without relying on an external linker.

Dynamic ELF libraries can be output but the C compiler does not generate position independent code (PIC). It means that the dynamic library code generated by TCC cannot be factorized among processes yet.

TCC linker eliminates unreferenced object code in libraries. A single pass is done on the object and library list, so the order in which object files and libraries are specified is important (same constraint as GNU ld). No grouping options (`--start-group' and `--end-group') are supported.

5.2 ELF file loader

TCC can load ELF object files, archives (.a files) and dynamic libraries (.so).

5.3 PE-i386 file generation

TCC for Windows supports the native Win32 executable file format (PE-i386). It generates EXE files (console and gui) and DLL files.

For usage on Windows, see also tcc-win32.txt.

5.4 GNU Linker Scripts

Because on many Linux systems some dynamic libraries (such as `/usr/lib/libc.so') are in fact GNU ld link scripts (horrible!), the TCC linker also supports a subset of GNU ld scripts.

The GROUP and FILE commands are supported. OUTPUT_FORMAT and TARGET are ignored.

Example from `/usr/lib/libc.so':

/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )

6. TinyCC Memory and Bound checks

This feature is activated with the `-b' (see section 2. Command line invocation).

Note that pointer size is unchanged and that code generated with bound checks is fully compatible with unchecked code. When a pointer comes from unchecked code, it is assumed to be valid. Even very obscure C code with casts should work correctly.

For more information about the ideas behind this method, see http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html.

Here are some examples of caught errors:

Invalid range with standard string function:
{
    char tab[10];
    memset(tab, 0, 11);
}
Out of bounds-error in global or local arrays:
{
    int tab[10];
    for(i=0;i<11;i++) {
        sum += tab[i];
    }
}
Out of bounds-error in malloc'ed data:
{
    int *tab;
    tab = malloc(20 * sizeof(int));
    for(i=0;i<21;i++) {
        sum += tab4[i];
    }
    free(tab);
}
Access of freed memory:
{
    int *tab;
    tab = malloc(20 * sizeof(int));
    free(tab);
    for(i=0;i<20;i++) {
        sum += tab4[i];
    }
}
Double free:
{
    int *tab;
    tab = malloc(20 * sizeof(int));
    free(tab);
    free(tab);
}

7. The libtcc library

The libtcc library enables you to use TCC as a backend for dynamic code generation.

Read the `libtcc.h' to have an overview of the API. Read `libtcc_test.c' to have a very simple example.

The idea consists in giving a C string containing the program you want to compile directly to libtcc. Then you can access to any global symbol (function or variable) defined.

8. Developer's guide

This chapter gives some hints to understand how TCC works. You can skip it if you do not intend to modify the TCC code.

8.1 File reading

The BufferedFile structure contains the context needed to read a file, including the current line number. tcc_open() opens a new file and tcc_close() closes it. inp() returns the next character.

8.2 Lexer

next() reads the next token in the current file. next_nomacro() reads the next token without macro expansion.

tok contains the current token (see TOK_xxx) constants. Identifiers and keywords are also keywords. tokc contains additional infos about the token (for example a constant value if number or string token).

8.3 Parser

The parser is hardcoded (yacc is not necessary). It does only one pass, except:

  • For initialized arrays with unknown size, a first pass is done to count the number of elements.
  • For architectures where arguments are evaluated in reverse order, a first pass is done to reverse the argument order.

8.4 Types

The types are stored in a single 'int' variable. It was choosen in the first stages of development when tcc was much simpler. Now, it may not be the best solution.

#define VT_INT        0  /* integer type */
#define VT_BYTE       1  /* signed byte type */
#define VT_SHORT      2  /* short type */
#define VT_VOID       3  /* void type */
#define VT_PTR        4  /* pointer */
#define VT_ENUM       5  /* enum definition */
#define VT_FUNC       6  /* function type */
#define VT_STRUCT     7  /* struct/union definition */
#define VT_FLOAT      8  /* IEEE float */
#define VT_DOUBLE     9  /* IEEE double */
#define VT_LDOUBLE   10  /* IEEE long double */
#define VT_BOOL      11  /* ISOC99 boolean type */
#define VT_LLONG     12  /* 64 bit integer */
#define VT_LONG      13  /* long integer (NEVER USED as type, only
                            during parsing) */
#define VT_BTYPE      0x000f /* mask for basic type */
#define VT_UNSIGNED   0x0010  /* unsigned type */
#define VT_ARRAY      0x0020  /* array type (also has VT_PTR) */
#define VT_BITFIELD   0x0040  /* bitfield modifier */

#define VT_STRUCT_SHIFT 16   /* structure/enum name shift (16 bits left) */

When a reference to another type is needed (for pointers, functions and structures), the 32 - VT_STRUCT_SHIFT high order bits are used to store an identifier reference.

The VT_UNSIGNED flag can be set for chars, shorts, ints and long longs.

Arrays are considered as pointers VT_PTR with the flag VT_ARRAY set.

The VT_BITFIELD flag can be set for chars, shorts, ints and long longs. If it is set, then the bitfield position is stored from bits VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11.

VT_LONG is never used except during parsing.

During parsing, the storage of an object is also stored in the type integer:

#define VT_EXTERN  0x00000080  /* extern definition */
#define VT_STATIC  0x00000100  /* static variable */
#define VT_TYPEDEF 0x00000200  /* typedef definition */

8.5 Symbols

All symbols are stored in hashed symbol stacks. Each symbol stack contains Sym structures.

Sym.v contains the symbol name (remember an idenfier is also a token, so a string is never necessary to store it). Sym.t gives the type of the symbol. Sym.r is usually the register in which the corresponding variable is stored. Sym.c is usually a constant associated to the symbol.

Four main symbol stacks are defined:

define_stack
for the macros (#defines).
global_stack
for the global variables, functions and types.
local_stack
for the local variables, functions and types.
global_label_stack
for the local labels (for goto).
label_stack
for GCC block local labels (see the __label__ keyword).

sym_push() is used to add a new symbol in the local symbol stack. If no local symbol stack is active, it is added in the global symbol stack.

sym_pop(st,b) pops symbols from the symbol stack st until the symbol b is on the top of stack. If b is NULL, the stack is emptied.

sym_find(v) return the symbol associated to the identifier v. The local stack is searched first from top to bottom, then the global stack.

8.6 Sections

The generated code and datas are written in sections. The structure Section contains all the necessary information for a given section. new_section() creates a new section. ELF file semantics is assumed for each section.

The following sections are predefined:

text_section
is the section containing the generated code. ind contains the current position in the code section.
data_section
contains initialized data
bss_section
contains uninitialized data
bounds_section
lbounds_section
are used when bound checking is activated
stab_section
stabstr_section
are used when debugging is actived to store debug information
symtab_section
strtab_section
contain the exported symbols (currently only used for debugging).

8.7 Code generation

8.7.1 Introduction

The TCC code generator directly generates linked binary code in one pass. It is rather unusual these days (see gcc for example which generates text assembly), but it can be very fast and surprisingly little complicated.

The TCC code generator is register based. Optimization is only done at the expression level. No intermediate representation of expression is kept except the current values stored in the value stack.

On x86, three temporary registers are used. When more registers are needed, one register is spilled into a new temporary variable on the stack.

8.7.2 The value stack

When an expression is parsed, its value is pushed on the value stack (vstack). The top of the value stack is vtop. Each value stack entry is the structure SValue.

SValue.t is the type. SValue.r indicates how the value is currently stored in the generated code. It is usually a CPU register index (REG_xxx constants), but additional values and flags are defined:

#define VT_CONST     0x00f0
#define VT_LLOCAL    0x00f1
#define VT_LOCAL     0x00f2
#define VT_CMP       0x00f3
#define VT_JMP       0x00f4
#define VT_JMPI      0x00f5
#define VT_LVAL      0x0100
#define VT_SYM       0x0200
#define VT_MUSTCAST  0x0400
#define VT_MUSTBOUND 0x0800
#define VT_BOUNDED   0x8000
#define VT_LVAL_BYTE     0x1000
#define VT_LVAL_SHORT    0x2000
#define VT_LVAL_UNSIGNED 0x4000
#define VT_LVAL_TYPE     (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)
VT_CONST
indicates that the value is a constant. It is stored in the union SValue.c, depending on its type.
VT_LOCAL
indicates a local variable pointer at offset SValue.c.i in the stack.
VT_CMP
indicates that the value is actually stored in the CPU flags (i.e. the value is the consequence of a test). The value is either 0 or 1. The actual CPU flags used is indicated in SValue.c.i. If any code is generated which destroys the CPU flags, this value MUST be put in a normal register.
VT_JMP
VT_JMPI
indicates that the value is the consequence of a conditional jump. For VT_JMP, it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted. These values are used to compile the || and && logical operators. If any code is generated, this value MUST be put in a normal register. Otherwise, the generated code won't be executed if the jump is taken.
VT_LVAL
is a flag indicating that the value is actually an lvalue (left value of an assignment). It means that the value stored is actually a pointer to the wanted value. Understanding the use VT_LVAL is very important if you want to understand how TCC works.
VT_LVAL_BYTE
VT_LVAL_SHORT
VT_LVAL_UNSIGNED
if the lvalue has an integer type, then these flags give its real type. The type alone is not enough in case of cast optimisations.
VT_LLOCAL
is a saved lvalue on the stack. VT_LLOCAL should be eliminated ASAP because its semantics are rather complicated.
VT_MUSTCAST
indicates that a cast to the value type must be performed if the value is used (lazy casting).
VT_SYM
indicates that the symbol SValue.sym must be added to the constant.
VT_MUSTBOUND
VT_BOUNDED
are only used for optional bound checking.

8.7.3 Manipulating the value stack

vsetc() and vset() pushes a new value on the value stack. If the previous vtop was stored in a very unsafe place(for example in the CPU flags), then some code is generated to put the previous vtop in a safe storage.

vpop() pops vtop. In some cases, it also generates cleanup code (for example if stacked floating point registers are used as on x86).

The gv(rc) function generates code to evaluate vtop (the top value of the stack) into registers. rc selects in which register class the value should be put. gv() is the most important function of the code generator.

gv2() is the same as gv() but for the top two stack entries.

8.7.4 CPU dependent code generation

See the `i386-gen.c' file to have an example.

load()
must generate the code needed to load a stack value into a register.
store()
must generate the code needed to store a register into a stack value lvalue.
gfunc_start()
gfunc_param()
gfunc_call()
should generate a function call
gfunc_prolog()
gfunc_epilog()
should generate a function prolog/epilog.
gen_opi(op)
must generate the binary integer operation op on the two top entries of the stack which are guaranted to contain integer types. The result value should be put on the stack.
gen_opf(op)
same as gen_opi() for floating point operations. The two top entries of the stack are guaranted to contain floating point values of same types.
gen_cvt_itof()
integer to floating point conversion.
gen_cvt_ftoi()
floating point to integer conversion.
gen_cvt_ftof()
floating point to floating point of different size conversion.
gen_bounded_ptr_add()
gen_bounded_ptr_deref()
are only used for bounds checking.

8.8 Optimizations done

Constant propagation is done for all operations. Multiplications and divisions are optimized to shifts when appropriate. Comparison operators are optimized by maintaining a special cache for the processor flags. &&, || and ! are optimized by maintaining a special 'jump target' value. No other jump optimization is currently performed because it would require to store the code in a more abstract fashion.

Concept Index

Jump to: _ - a - b - c - d - e - f - g - i - j - l - m - o - p - q - r - s - t - u - v - w

_

  • __asm__

    • a

  • align directive
  • aligned attribute
  • ascii directive
  • asciz directive
  • assembler
  • assembler directives
  • assembly, inline

    • b

  • bound checks
  • bss directive
  • byte directive

    • c

  • caching processor flags
  • cdecl attribute
  • code generation
  • comparison operators
  • constant propagation
  • CPU dependent

    • d

  • data directive
  • directives, assembler
  • dllexport attribute

    • e

  • ELF

    • f

  • FILE, linker command
  • fill directive
  • flags, caching

    • g

  • gas
  • global directive
  • globl directive
  • GROUP, linker command

    • i

  • inline assembly
  • int directive

    • j

  • jump optimization

    • l

  • linker
  • linker scripts
  • long directive

    • m

  • memory checks

    • o

  • optimizations
  • org directive
  • OUTPUT_FORMAT, linker command

    • p

  • packed attribute
  • PE-i386
  • previous directive

    • q

  • quad directive

    • r

  • regparm attribute

    • s

  • scripts, linker
  • section attribute
  • section directive
  • short directive
  • skip directive
  • space directive
  • stdcall attribute
  • strength reduction
  • string directive

    • t

  • TARGET, linker command
  • text directive

    • u

  • unused attribute

    • v

  • value stack
  • value stack, introduction

    • w

  • word directive

    • This document was generated on 21 May 2009 using texi2html 1.56k.


TinyCC Changelog

version 0.9.26:

User interface:
- -MD/-MF (automatically generate dependencies for make)
- -pthread option (same as -D_REENTRANT -lpthread) (Henry Kroll III)
- -m32/-m64 to re-exec cross compiler (Henry Kroll III)
- -Wl, Mimic all GNU -option forms supported by ld (Kirill Smelkov)
- new LIBTCCAPI tcc_set_options() (grischka)

Platforms:
- Many improvements for x86-64 target (Shinichiro Hamaji, Michael Matz, grischka)
- x86-64 assembler (Frederic Feret)
- Many improvements for ARM target (Daniel Gl�ckner, Thomas Preud'homme)
- Support WinCE PE ARM (Timo VJ Lahde)
- Support ARM hardfloat calling convention (Thomas Preud'homme)
- Support SELinux (Security-Enhanced Linux) (Henry Kroll III)
- Support Debian GNU/kFreeBSD kernels (Pierre Chifflier)
- Support GNU/Hurd kernels (Thomas Preud'homme)
- Support OSX (tcc -run only) (Milutin Jovanovic)
- Support multiarch configuration (Thomas Preud'homme)
- Support out-of-tree build (Akim Demaille)

Features:
- C99 variable length arrays (Thomas Preud'homme & Joe Soroka)
- Asm labels for variables and functions (Thomas Preud'homme)
- STT_GNU_IFUNC (Indirect functions as externals) (Thomas Preud'homme)
- More tests (tests2) (Milutin Jovanovic)

version 0.9.25:

- first support for x86-64 target (Shinichiro Hamaji)
- support uClibc
- split tcc.c into tcc.h libtcc.c tccpp.c tccgen.c tcc.c
- improved preprocess output with linenumbers and spaces preserved
- tcc_relocate now copies code into user buffer
- fix bitfields with non-int types and in unions
- improve ARM cross-compiling (Daniel Gl�ckner)
- link stabstr sections from multiple objects
- better (still limited) support for multiple TCCStates

version 0.9.24:

- added verbosity levels -v, -vv, -vvv
- Accept standard input as an inputstream (Hanzac Chen)
- Support c89 compilers other than gcc (Hanzac Chen)
- -soname linker option (Marc Andre Tanner)
- Just warn about unknown directives, ignore quotes in #error/#warning
- Define __STDC_VERSION__=199901L (477)
- Switch to newer tccpe.c (includes support for resources)
- Handle backslashes within #include/#error/#warning
- Import changesets (part 4) 428,457,460,467: defines for openbsd etc.
- Use _WIN32 for a windows hosted tcc and define it for the PE target,
  otherwise define __unix / __linux (Detlef Riekenberg)
- Import changesets (part 3) 409,410: ARM EABI by Daniel Gl�ckner
- Some in-between fixes:
  TCC -E no longer hangs with macro calls involving newlines.
  (next_nomacro1 now advances the read-pointer with TOK_LINEFEED)
  Global cast (int g_i = 1LL;) no longer crashes tcc.
  (nocode_wanted is initially 1, and only 0 for gen_function)
  On win32 now tcc.exe finds 'include' & 'lib' even if itself is in 'bin'.
  (new function w32_tcc_lib_path removes 'bin' if detected)
  Added quick build batch file for mingw (win32/build-tcc.bat)
  Last added case label optimization (455) produced wrong code. Reverted.

- Import more changesets from Rob Landley's fork (part 2):
  487: Handle long long constants in gen_opic() (Rob Landley)
  484: Handle parentheses within __attribute__((...)) (Rob Landley)
  480: Remove a goto in decl_initializer_alloc (Rob Landley)
  475: Fix dereferences in inline assembly output (Joshua Phillips)
  474: Cast ptrs to ints of different sizes correctly (Joshua Phillips)
  473: Fix size of structs with empty array member (Joshua Phillips)
  470: No warning for && and || with mixed pointers/integers (Rob Landley)
  469: Fix symbol visibility problems in the linker (Vincent Pit)
  468: Allow && and || involving pointer arguments (Rob Landley)
  455: Optimize case labels with no code in between (Zdenek Pavlas)
  450: Implement alloca for x86 (grischka)
  415: Parse unicode escape sequences (Axel Liljencrantz)
  407: Add a simple va_copy() in stdarg.h (Hasso Tepper)
  400: Allow typedef names as symbols (Dave Dodge)

- Import some changesets from Rob Landley's fork (part 1):
  462: Use LGPL with bcheck.c and il-gen.c
  458: Fix global compound literals (in unary: case '&':) (Andrew Johnson)
  456: Use return code from tcc_output_file in main() (Michael Somos)
  442: Fix indirections with function pointers (***fn)() (grischka)
  441: Fix LL left shift in libtcc1.c:__shldi3 (grischka)
  440: Pass structures and function ptrs through ?: (grischka)
  439: Keep rvalue in bit assignment (bit2 = bit1 = x) (grischka)
  438: Degrade nonportable pointer assignment to warning (grischka)
  437: Call 'saveregs()' before jumping with logical and/or/not (grischka)
  435: Put local static variables into global memory (grischka)
  432/434: Cast double and ptr to bool (grischka)
  420: Zero pad x87 tenbyte long doubles (Felix Nawothnig)
  417: Make 'sizeof' unsigned (Rob Landley)
  397: Fix save_reg for longlongs (Daniel Gl�ckner)
  396: Fix "invalid relocation entry" problem on ubuntu - (Bernhard Fischer)

- ignore AS_NEEDED ld command
- mark executable sections as executable when running in memory
- added support for win32 wchar_t (Filip Navara)
- segment override prefix support (Filip Navara)
- normalized slashes in paths (Filip Navara)
- windows style fastcall (Filip Navara)
- support for empty input register section in asm (Filip Navara)
- anonymous union/struct support (Filip Navara)
- fixed parsing of function parameters
- workaround for function pointers in conditional expressions (Dave Dodge)
- initial '-E' option support to use the C preprocessor alone
- discard type qualifiers when comparing function parameters (Dave Dodge)
- Bug fix: A long long value used as a test expression ignores the
  upper 32 bits at runtime (Dave Dodge)
- fixed multiple concatenation of PPNUM tokens (initial patch by Dave Dodge)
- fixed multiple typedef specifiers handling
- fixed sign extension in some type conversions (Dave Dodge)

version 0.9.23:

- initial PE executable format for windows version (grischka)
- '#pragma pack' support (grischka)
- '#include_next' support (Bernhard Fischer)
- ignore '-pipe' option
- added -f[no-]leading-underscore
- preprocessor function macro parsing fix (grischka)

version 0.9.22:

- simple memory optimisations: kernel compilation is 30% faster
- linker symbol definitions fixes
- gcc 3.4 fixes
- fixed value stack full error
- 'packed' attribute support for variables and structure fields
- ignore 'const' and 'volatile' in function prototypes
- allow '_Bool' in bit fields

version 0.9.21:

- ARM target support (Daniel Glöckner)
- added '-funsigned-char, '-fsigned-char' and
  '-Wimplicit-function-declaration'
- fixed assignment of const struct in struct
- line comment fix (reported by Bertram Felgenhauer)
- initial TMS320C67xx target support (TK)
- win32 configure
- regparm() attribute
- many built-in assembler fixes
- added '.org', '.fill' and '.previous' assembler directives
- '-fno-common' option
- '-Ttext' linker option
- section alignment fixes
- bit fields fixes
- do not generate code for unused inline functions
- '-oformat' linker option.
- added 'binary' output format.

version 0.9.20:

- added '-w' option
- added '.gnu.linkonce' ELF sections support
- fixed libc linking when running in memory (avoid 'stat' function
  errors).
- extended '-run' option to be able to give several arguments to a C
  script.

version 0.9.19:

- "alacarte" linking (Dave Long)
- simpler function call
- more strict type checks
- added 'const' and 'volatile' support and associated warnings
- added -Werror, -Wunsupported, -Wwrite-strings, -Wall.
- added __builtin_types_compatible_p() and __builtin_constant_p()
- chars support in assembler (Dave Long)
- .string, .globl, .section, .text, .data and .bss asm directive
  support (Dave Long)
- man page generated from tcc-doc.texi
- fixed macro argument substitution
- fixed zero argument macro parsing
- changed license to LGPL
- added -rdynamic option support

version 0.9.18:

- header fix (time.h)
- fixed inline asm without operand case
- fixed 'default:' or 'case x:' with '}' after (incorrect C construct accepted
  by gcc)
- added 'A' inline asm constraint.

version 0.9.17:

- PLT generation fix
- tcc doc fixes (Peter Lund)
- struct parse fix (signaled by Pedro A. Aranda Gutierrez)
- better _Bool lvalue support (signaled by Alex Measday)
- function parameters must be converted to pointers (signaled by Neil Brown)
- sanitized string and character constant parsing
- fixed comment parse (signaled by Damian M Gryski)
- fixed macro function bug (signaled by Philippe Ribet)
- added configure (initial patch by Mitchell N Charity)
- added '-run' and '-v' options (initial patch by vlindos)
- added real date report in __DATE__ and __TIME__ macros

version 0.9.16:

- added assembler language support
- added GCC inline asm() support
- fixed multiple variable definitions : uninitialized variables are
  created as COMMON symbols.
- optimized macro processing
- added GCC statement expressions support
- added GCC local labels support
- fixed array declaration in old style function parameters
- support casts in static structure initializations
- added various __xxx[__] keywords for GCC compatibility
- ignore __extension__ GCC in an expression or in a type (still not perfect)
- added '? :' GCC extension support

version 0.9.15:

- compilation fixes for glibc 2.2, gcc 2.95.3 and gcc 3.2.
- FreeBSD compile fixes. Makefile patches still missing (Carl Drougge).
- fixed file type guessing if '.' is in the path.
- fixed tcc_compile_string()
- add a dummy page in ELF files to fix RX/RW accesses (pageexec at
  freemail dot hu).

version 0.9.14:

- added #warning. error message if invalid preprocessing directive.
- added CType structure to ease typing (faster parse).
- suppressed secondary hash tables (faster parse).
- rewrote parser by optimizing common cases (faster parse).
- fixed signed long long comparisons.
- fixed 'int a(), b();' declaration case.
- fixed structure init without '{}'.
- correct alignment support in structures.
- empty structures support.
- gcc testsuite now supported.
- output only warning if implicit integer/pointer conversions.
- added static bitfield init.

version 0.9.13:

- correct preprocessing token pasting (## operator) in all cases (added
  preprocessing number token).
- fixed long long register spill.
- fixed signed long long '>>'.
- removed memory leaks.
- better error handling : processing can continue on link errors. A
  custom callback can be added to display error messages. Most
  errors do not call exit() now.
- ignore -O, -W, -m and -f options
- added old style function declarations
- added GCC __alignof__ support.
- added GCC typeof support.
- added GCC computed gotos support.
- added stack backtrace in runtime error message. Improved runtime
  error position display.

version 0.9.12:

- more fixes for || and && handling.
- improved '? :' type handling.
- fixed bound checking generation with structures
- force '#endif' to be in same file as matching '#if'
- #include file optimization with '#ifndef #endif' construct detection
- macro handling optimization
- added tcc_relocate() and tcc_get_symbol() in libtcc.

version 0.9.11:

- stdarg.h fix for double type (thanks to Philippe Ribet).
- correct white space characters and added MSDOS newline support.
- fixed invalid implicit function call type declaration.
- special macros such as __LINE__ are defined if tested with defined().
- fixed '!' operator with relocated address.
- added symbol + offset relocation (fixes some static variable initializers)
- '-l' option can be specified anywhere. '-c' option yields default
  output name. added '-r' option for relocatable output.
- fixed '\nnn' octal parsing.
- fixed local extern variables declarations.

version 0.9.10:

- fixed lvalue type when saved in local stack.
- fixed '#include' syntax when using macros.
- fixed '#line' bug.
- removed size limit on strings. Unified string constants handling
  with variable declarations.
- added correct support for '\xX' in wchar_t strings.
- added support for bound checking in generated executables
- fixed -I include order.
- fixed incorrect function displayed in runtime error.

version 0.9.9:

- fixed preprocessor expression parsing for #if/#elif.
- relocated debug info (.stab section).
- relocated bounds info (.bounds section).
- fixed cast to char of char constants ('\377' is -1 instead of 255)
- fixed implicit cast for unary plus.
- strings and '__func__' have now 'char[]' type instead of 'char *'
  (fixes sizeof() return value).
- added __start_xxx and __stop_xxx symbols in linker.
- better DLL creation support (option -shared begins to work).
- ELF sections and hash tables are resized dynamically.
- executables and DLLs are stripped by default.

version 0.9.8:

- First version of full ELF linking support (generate objects, static
  executable, dynamic executable, dynamic libraries). Dynamic library
  support is not finished (need PIC support in compiler and some
  patches in symbol exporting).
- First version of ELF loader for object (.o) and archive (.a) files.
- Support of simple GNU ld scripts (GROUP and FILE commands)
- Separated runtime library and bound check code from TCC (smaller
  compiler core).
- fixed register reload in float compare.
- fixed implicit char/short to int casting.
- allow array type for address of ('&') operator.
- fixed unused || or && result.
- added GCC style variadic macro support.
- optimized bound checking code for array access.
- tcc includes are now in $(prefix)/lib/tcc/include.
- more command line options - more consistent handling of multiple
  input files.
- added tcc man page (thanks to Cyril Bouthors).
- uClibc Makefile update
- converted documentation to texinfo format.
- added developper's guide in documentation.

version 0.9.7:

- added library API for easy dynamic compilation (see libtcc.h - first
  draft).
- fixed long long register spill bug.
- fixed '? :' register spill bug.

version 0.9.6:

- added floating point constant propagation (fixes negative floating
  point constants bug).

version 0.9.5:

 - uClibc patches (submitted by Alfonso Martone).
 - error reporting fix
 - added CONFIG_TCC_BCHECK to get smaller code if needed.

version 0.9.4:

 - windows port (currently cannot use -g, -b and dll functions).
 - faster and simpler I/O handling.
 - '-D' option works in all cases.
 - preprocessor fixes (#elif and empty macro args)
 - floating point fixes
 - first code for CIL generation (does not work yet)

version 0.9.3:

 - better and smaller code generator.
 - full ISOC99 64 bit 'long long' support.
 - full 32 bit 'float', 64 bit 'double' and 96 bit 'long double' support.
 - added '-U' option.
 - added assembly sections support.
 - even faster startup time by mmaping sections instead of mallocing them.
 - added GNUC __attribute__ keyword support (currently supports
    'section' and 'aligned' attributes).
 - added ELF file output (only usable for debugging now)
 - added debug symbol generation (STAB format).
 - added integrated runtime error analysis ('-g' option: print clear
   run time error messages instead of "Segmentation fault").
 - added first version of tiny memory and bound checker ('-b' option).

version 0.9.2:

 - even faster parsing.
 - various syntax parsing fixes.
 - fixed external relocation handling for variables or functions pointers.
 - better function pointers type handling.
 - can compile multiple files (-i option).
 - ANSI C bit fields are supported.
 - beginning of float/double/long double support.
 - beginning of long long support.

version 0.9.1:

 - full ISOC99 initializers handling.
 - compound literals.
 - structures handle in assignments and as function param or return value.
 - wide chars and strings.
 - macro bug fix

version 0.9:
 - initial version.
Copyright (c) 2001-2009 Fabrice Bellard
Fabrice Bellard - http://bellard.org/ - http://www.tinycc.org/


TinyGL : a Small, Free and Fast Subset of OpenGL*

News

(Mar 17 2002) TinyGL 0.4 is out (Changelog)

Download

Get it: TinyGL-0.4.tar.gz

Introduction

TinyGL is intended to be a very small implementation of a subset of OpenGL * for embedded systems or games. It is a software only implementation. Only the main OpenGL calls are implemented.

The main strength of TinyGL is that it is fast and simple because it has not to be exactly compatible with OpenGL. In particular, the texture mapping and the geometrical transformations are very fast. TinyGL is a lot faster than Mesa or the software Solaris OpenWin OpenGL implementation for the VReng Virtual Reality engine for example.

The main features of TinyGL are:

  • Header compatible with OpenGL (the headers are adapted from the very good Mesa by Brian Paul et al.)
  • Zlib-like licence for easy integration in commercial designs (read the LICENCE file).
  • Subset of GLX for easy testing with X Window.
  • GLX like API (NGLX) to use it with NanoX in Microwindows.
  • Subset of BGLView under BeOS (thank to Peder Blekken).
  • OpenGL like lightening.
  • Limited support of OpenGL 1.1 arrays.
  • Complete OpenGL selection mode handling for object picking.
  • 16 bit Z buffer. 16 bit RGB display. High speed dithering to paletted 8 bits if needed. High speed convertion to 24 or 32 bits.
  • Fast Gouraud shadding optimized for 16 bit RGB.
  • Fast texture mapping capabilities, with perspective correction and texture objects.
  • 32 bit float only arithmetic.
  • Very small: compiled code size of about 40 kB on x86.
  • C sources for GCC on 32/64 bit architectures. It has been tested succesfully on x86-Linux and sparc-Solaris.

Architecture

TinyGL is made up four main modules:
  • Mathematical routines (zmath).
  • OpenGL-like emulation (zgl).
  • Z buffer and rasterisation (zbuffer).
  • GLX interface (zglx).
To use TinyGL in an embedded system, you should look at the GLX layer and modify it to suit your need. Adding a more user friendly developper layer (as in Mesa) may be useful.

Why ?

TinyGL was developped as a student project for a Virtual Reality network system called VReng (see the VReng home page ).

At that time (January 1997), my initial project was to write my own 3D rasterizer based on some old sources I wrote. But I realized that it would be better to use OpenGL to work on any platform. My problem was that I wanted to use texture mapping which was (and is still) quite slower on many software OpenGL implementation. I could have modified Mesa to suit my needs, but I really wanted to use my old sources for that project.

I finally decided to use the same syntax as OpenGL but with my own libraries, thinking that later it could ease the porting of VReng to OpenGL.

Now VReng is at last compatible with OpenGL, and I managed to patch TinyGL so that VReng can still work with it without any modifications.

Since TinyGL may be useful for some people, especially in the world of embedded designs, I decided to release it 'as is', otherwise, it would have been lost on my hard disk !

Links

  • The Mesa 3D Graphics Library.
  • The OpenGL site.
  • The Microwindows site.
  • The VReng Virtual Reality engine.
anybrowser
* OpenGL(R) is a registered trademark of Silicon Graphics, Inc.
Fabrice Bellard - http://bellard.org/
last update: Mar 17, 2002


Changelog for TinyGL

version 0.4

 - added 24/32 bit rendering support (Olivier Landemarre - F. Bellard)
 - fixed GL_TRIANGLE_STRIP (Olivier Landemarre)
 - added gl_malloc, gl_free, gl_zalloc wrappers (Olivier Landemarre)

version 0.3

 - added NanoX API (nglx) (F. Bellard)
 - added gears example and unified GUI in examples (F. Bellard)
 - added TGL_FEATURE_RENDER_BITS so that it will be possible to render
   natively in 15/16/24 or 32 bits. (F. Bellard)
 - interpolated lines (Olivier Landemarre)
 - fast no shading case (Olivier Landemarre)
 - fast no projection case (Olivier Landemarre)

version 0.2

 (F. Bellard)
 - added 24/32 bpp support. Added some features.h ifdefs.
 - fixed some error reporting cases in the examples
 - endianness is deduced from the glibc (BYTE_ORDER macro)

version 0.19

 (Peder Blekken)
 - new files BeOS/* src/msghandling.*, src/arrays.*, src/oscontext.c
     include/GL/oscontext.h src/features.h
 - added support for BeOS, see README.BEOS
 - added support for drawing convex polygons with unlimited # of vertices
 - added support for GL_LIGHT_MODEL_TWO_SIDE
 - added generic rotation code for glopRotate
 - added support for opengl 1.1 arrays
 - added support for glPolygonOffset, not implemented.
 - added glGetFloatv, limited support.
 - added some pnames for glGetIntegerv
 - added some empty functions in include/GL/gl.h to compile VRMLView
 - added GL_VERSION_1_1 define in include/GL/gl.h
 - fixed "bug" when context->gl_resize_viewport is not set.
 - fixed bug in glBindTexture (didn't accept texture object 0)

version 0.1

 - Initial revision, Fabrice Bellard


ASM Mode Reel

    TinyCC       ( Vu dans  tcc-win32.txt )
    ===================================================================

    This file contains specific information for usage of TinyCC
    under MS-Windows.  See tcc-doc.html to have all the features.

    Installation from the binary ZIP package:
    -----------------------------------------
    Unzip the package to a directory of your choice.

    Set the system PATH:
    --------------------
    To be able to invoke the compiler from everywhere on your computer by
    just typing "tcc", please add the directory containing tcc.exe to your
    system PATH.

    Examples:
    ---------
    Open a console window (DOS box) and 'cd' to the examples directory.

    For the 'Fibonacci' example type:

    tcc fib.c

    For the 'Hello Windows' GUI example type:

    tcc hello_win.c

    For the 'Hello DLL' example type

    tcc -shared dll.c
    tiny_impdef dll.dll (optional)
        tcc hello_dll.c dll.def

    Using libtcc as JIT compiler in your program
    --------------------------------------------
    Check out the 'libtcc_test' example:

    - Running it from source:
        tcc -I libtcc libtcc/libtcc.def -run examples/libtcc_test.c

    - Compiling with TCC:
        tcc examples/libtcc_test.c -I libtcc libtcc/libtcc.def

    - Compiling with MinGW:
        gcc examples/libtcc_test.c -I libtcc libtcc.dll

    - Compiling with MSVC:
        lib /def:libtcc\libtcc.def /out:libtcc.lib
        cl /MD examples/libtcc_test.c -I libtcc libtcc.lib

    Import Definition Files:
    ------------------------
    To link with Windows system DLLs, TCC uses import definition
    files (.def) instead of libraries.

    The included 'tiny_impdef' program may be used to make additional
    .def files for any DLL. For example:

        tiny_impdef.exe opengl32.dll

    Put opengl32.def into the tcc/lib directory.  Specify -lopengl32 at
    the TCC commandline to link a program that uses opengl32.dll.

     A placer le header files opengl32.h dans le dir include de Tcc64
    (récupérer dans un system compilater C Bcc555 ou Lcc-Win32 ..)

    Header Files:
    -------------
    The system header files (except _mingw.h) are from the MinGW
    distribution:

    http://www.mingw.org/

    From the windows headers, only a minimal set is included.  If you need
    more,  get MinGW's "w32api" package.  Extract the files from "include"
    into your "tcc/include/winapi" directory.

    Resource Files:
    ---------------
    TCC can link windows resources in coff format as generated by MinGW's
    windres.exe.  For example:

        windres -O coff app.rc -o appres.o
        tcc app.c appres.o -o app.exe

    Tiny Libmaker:
    --------------
    The included tiny_libmaker tool by Timovj Lahde can be used as
    'ar' replacement to make a library from several object files:

    tiny_libmaker [rcs] library objectfiles ...

    Compilation from source:
    ------------------------
    * You can use the MinGW and MSYS tools available at

        http://www.mingw.org

      Untar the TCC archive and type in the MSYS shell:

        ./configure [--prefix installpath]
        make
        make install

    The default install location is c:\Program Files\tcc

    * Alternatively you can compile TCC with just GCC from MinGW using

        build-tcc.bat (from the win32 directory)

      To install, copy the entire contents of the win32 directory to
      where you want.

    Limitations:
    ------------
    - On the object file level, currently TCC supports only the ELF format,
      not COFF as used by MinGW and MSVC.  It is not possible to exchange
      object files or libraries between TCC and these compilers.  However
      libraries for TCC from objects by TCC can be made using tiny_libmaker
      or MinGW's ar.

    - No leading underscore is generated in the ELF symbols.

    - Bounds checking (option -b) is not supported on 64-bit OS.

    Documentation and License:
    --------------------------
    TCC is distributed under the GNU Lesser General Public License. (See
    COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html)

    TinyCC homepage is at:

    http://fabrice.bellard.free.fr/tcc/

    WinAPI Help and 3rd-party tools:
    --------------------------------
    The Windows API documentation (Win95) in a single .hlp file is
    available on the lcc-win32 site as "win32hlp.exe" or from other
    locations as "win32hlp_big.zip".

    A nice RAD tool to create windows resources (dialog boxes etc.) is
    "ResEd", available at the RadASM website.

    --- grischka


ASM Mode Reel

          ( Vu dans Library Libtcc.DEF )

LIBRARY libtcc.dll

EXPORTS
pstrcat
pstrcpy
pstrncpy
tcc_add_file
tcc_add_include_path
tcc_add_library
tcc_add_library_path
tcc_add_symbol
tcc_add_sysinclude_path
tcc_basename
tcc_compile_string
tcc_define_symbol
tcc_delete
tcc_error
tcc_error_noabort
tcc_fileextension
tcc_free
tcc_get_symbol
tcc_malloc
tcc_mallocz
tcc_memstats
tcc_new
tcc_output_file
tcc_parse_args
tcc_print_stats
tcc_realloc
tcc_relocate
tcc_run
tcc_set_error_func
tcc_set_lib_path
tcc_set_options
tcc_set_output_type
tcc_strdup
tcc_undefine_symbol
tcc_warning


ASM Mode Reel

      ( Vu dans le file  LIBTCC.H )

#ifndef LIBTCC_H
#define LIBTCC_H

#ifndef LIBTCCAPI
# define LIBTCCAPI
#endif

#ifdef __cplusplus
extern "C" {
#endif

struct TCCState;

typedef struct TCCState TCCState;

/* create a new TCC compilation context */
LIBTCCAPI TCCState *tcc_new(void);

/* free a TCC compilation context */
LIBTCCAPI void tcc_delete(TCCState *s);

/* set CONFIG_TCCDIR at runtime */
LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path);

/* set error/warning display callback */
LIBTCCAPI void tcc_set_error_func(TCCState *s, void *error_opaque,
    void (*error_func)(void *opaque, const char *msg));

/* set options as from command line (multiple supported) */
LIBTCCAPI int tcc_set_options(TCCState *s, const char *str);

/*****************************/
/* preprocessor */

/* add include path */
LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname);

/* add in system include path */
LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname);

/* define preprocessor symbol 'sym'. Can put optional value */
LIBTCCAPI void tcc_define_symbol(TCCState *s, const char *sym, const char *value);

/* undefine preprocess symbol 'sym' */
LIBTCCAPI void tcc_undefine_symbol(TCCState *s, const char *sym);

/*****************************/
/* compiling */

/* add a file (C file, dll, object, library, ld script). Return -1 if error. */
LIBTCCAPI int tcc_add_file(TCCState *s, const char *filename);

/* compile a string containing a C source. Return -1 if error. */
LIBTCCAPI int tcc_compile_string(TCCState *s, const char *buf);

/*****************************/
/* linking commands */

/* set output type. MUST BE CALLED before any compilation */
LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type);
#define TCC_OUTPUT_MEMORY   0 /* output will be run in memory (default) */
#define TCC_OUTPUT_EXE      1 /* executable file */
#define TCC_OUTPUT_DLL      2 /* dynamic library */
#define TCC_OUTPUT_OBJ      3 /* object file */
#define TCC_OUTPUT_PREPROCESS 4 /* only preprocess (used internally) */

/* equivalent to -Lpath option */
LIBTCCAPI int tcc_add_library_path(TCCState *s, const char *pathname);

/* the library name is the same as the argument of the '-l' option */
LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname);

/* add a symbol to the compiled program */
LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, const void *val);

/* output an executable, library or object file. DO NOT call
   tcc_relocate() before. */
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename);

/* link and run main() function and return its value. DO NOT call
   tcc_relocate() before. */
LIBTCCAPI int tcc_run(TCCState *s, int argc, char **argv);

/* do all relocations (needed before using tcc_get_symbol()) */
LIBTCCAPI int tcc_relocate(TCCState *s1, void *ptr);
/* possible values for 'ptr':
   - TCC_RELOCATE_AUTO : Allocate and manage memory internally
   - NULL              : return required memory size for the step below
   - memory address    : copy code to memory passed by the caller
   returns -1 if error. */
#define TCC_RELOCATE_AUTO (void*)1

/* return symbol value or NULL if not found */
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name);

#ifdef __cplusplus
}
#endif

#endif


Accueil

Accueil CHM

Normal, dit comme ça,
vous ne risquez pas de comprendre.


Tiny C Compiler Reference Documentation

This manual documents version 0.9.26 of the Tiny C Compiler.

1. Introduction | Introduction to tcc.
2. Command line invocation | Invocation of tcc (command line, options).
3. C language support | ANSI C and extensions.
4. TinyCC Assembler | Assembler syntax.
5. TinyCC Linker | Output file generation and supported targets.
6. TinyCC Memory and Bound checks | Automatic bounds-checking of C code.
7. The libtcc library | The libtcc library.
8. Developer's guide | Guide for Developers.

1. Introduction

TinyCC (aka TCC) is a small but hyper fast C compiler. Unlike other C compilers, it is meant to be self-relying: you do not need an external assembler or linker because TCC does that for you.

TCC compiles so fast that even for big projects Makefiles may not be necessary.

TCC not only supports ANSI C, but also most of the new ISO C99 standard and many GNUC extensions including inline assembly.

TCC can also be used to make C scripts, i.e. pieces of C source that you run as a Perl or Python script. Compilation is so fast that your script will be as fast as if it was an executable.

TCC can also automatically generate memory and bound checks (see section 6. TinyCC Memory and Bound checks) while allowing all C pointers operations. TCC can do these checks even if non patched libraries are used.

With libtcc, you can use TCC as a backend for dynamic code generation (see section 7. The libtcc library).

TCC mainly supports the i386 target on Linux and Windows. There are alpha ports for the ARM (arm-tcc) and the TMS320C67xx targets (c67-tcc). More information about the ARM port is available at http://lists.gnu.org/archive/html/tinycc-devel/2003-10/msg00044.html.

For usage on Windows, see also tcc-win32.txt.

2. Command line invocation

2.1 Quick start

usage: tcc [options] [infile1 infile2...] [`-run' infile args...]

TCC options are a very much like gcc options. The main difference is that TCC can also execute directly the resulting program and give it runtime arguments.

Here are some examples to understand the logic:

`tcc -run a.c'
Compile `a.c' and execute it directly

`tcc -run a.c arg1'
Compile a.c and execute it directly. arg1 is given as first argument to the main() of a.c.

`tcc a.c -run b.c arg1'
Compile `a.c' and `b.c', link them together and execute them. arg1 is given as first argument to the main() of the resulting program.

`tcc -o myprog a.c b.c'
Compile `a.c' and `b.c', link them and generate the executable `myprog'.

`tcc -o myprog a.o b.o'
link `a.o' and `b.o' together and generate the executable `myprog'.

`tcc -c a.c'
Compile `a.c' and generate object file `a.o'.

`tcc -c asmfile.S'
Preprocess with C preprocess and assemble `asmfile.S' and generate object file `asmfile.o'.

`tcc -c asmfile.s'
Assemble (but not preprocess) `asmfile.s' and generate object file `asmfile.o'.

`tcc -r -o ab.o a.c b.c'
Compile `a.c' and `b.c', link them together and generate the object file `ab.o'.

Scripting:

TCC can be invoked from scripts, just as shell scripts. You just need to add #!/usr/local/bin/tcc -run at the start of your C source:

#!/usr/local/bin/tcc -run
#include <stdio.h>

int main()
{
    printf("Hello World\n");
    return 0;
}

TCC can read C source code from standard input when `-' is used in place of `infile'. Example:

echo 'main(){puts("hello");}' | tcc -run -

2.2 Option summary

General Options:

`-c'
Generate an object file.

`-o outfile'
Put object file, executable, or dll into output file `outfile'.

`-run source [args...]'
Compile file source and run it with the command line arguments args. In order to be able to give more than one argument to a script, several TCC options can be given after the `-run' option, separated by spaces:
tcc "-run -L/usr/X11R6/lib -lX11" ex4.c
In a script, it gives the following header:
#!/usr/local/bin/tcc -run -L/usr/X11R6/lib -lX11

`-dumpversion'
Print only the compiler version and nothing else.

`-v'
Display TCC version.

`-vv'
Show included files. As sole argument, print search dirs (as below).

`-bench'
Display compilation statistics.

`-print-search-dirs'
Print the configured installation directory and a list of library and include directories tcc will search.

Preprocessor options:

`-Idir'
Specify an additional include path. Include paths are searched in the order they are specified.

System include paths are always searched after. The default system include paths are: `/usr/local/include', `/usr/include' and `PREFIX/lib/tcc/include'. (`PREFIX' is usually `/usr' or `/usr/local').

`-Dsym[=val]'
Define preprocessor symbol `sym' to val. If val is not present, its value is `1'. Function-like macros can also be defined: `-DF(a)=a+1'

`-Usym'
Undefine preprocessor symbol `sym'.

Compilation flags:

Note: each of the following warning options has a negative form beginning with `-fno-'.

`-funsigned-char'
Let the char type be unsigned.

`-fsigned-char'
Let the char type be signed.

`-fno-common'
Do not generate common symbols for uninitialized data.

`-fleading-underscore'
Add a leading underscore at the beginning of each C symbol.

Warning options:

`-w'
Disable all warnings.

Note: each of the following warning options has a negative form beginning with `-Wno-'.

`-Wimplicit-function-declaration'
Warn about implicit function declaration.

`-Wunsupported'
Warn about unsupported GCC features that are ignored by TCC.

`-Wwrite-strings'
Make string constants be of type const char * instead of char *.

`-Werror'
Abort compilation if warnings are issued.

`-Wall'
Activate all warnings, except `-Werror', `-Wunusupported' and `-Wwrite-strings'.

Linker options:

`-Ldir'
Specify an additional static library path for the `-l' option. The default library paths are `/usr/local/lib', `/usr/lib' and `/lib'.

`-lxxx'
Link your program with dynamic library libxxx.so or static library libxxx.a. The library is searched in the paths specified by the `-L' option.

`-Bdir'
Set the path where the tcc internal libraries (and include files) can be found (default is `PREFIX/lib/tcc').

`-shared'
Generate a shared library instead of an executable.

`-soname name'
set name for shared library to be used at runtime

`-static'
Generate a statically linked executable (default is a shared linked executable).

`-rdynamic'
Export global symbols to the dynamic linker. It is useful when a library opened with dlopen() needs to access executable symbols.

`-r'
Generate an object file combining all input files.

`-Wl,-rpath=path'
Put custom seatch path for dynamic libraries into executable.

`-Wl,--oformat=fmt'
Use fmt as output format. The supported output formats are:
elf32-i386
ELF output format (default)
binary
Binary image (only for executable output)
coff
COFF output format (only for executable output for TMS320C67xx target)

`-Wl,-subsystem=console/gui/wince/...'
Set type for PE (Windows) executables.

`-Wl,-[Ttext=# | section-alignment=# | file-alignment=# | image-base=# | stack=#]'
Modify executable layout.

`-Wl,-Bsymbolic'
Set DT_SYMBOLIC tag.

Debugger options:

`-g'
Generate run time debug information so that you get clear run time error messages: test.c:68: in function 'test5()': dereferencing invalid pointer instead of the laconic Segmentation fault.

`-b'
Generate additional support code to check memory allocations and array/pointer bounds. `-g' is implied. Note that the generated code is slower and bigger in this case.

Note: `-b' is only available on i386 for the moment.

`-bt N'
Display N callers in stack traces. This is useful with `-g' or `-b'.

Misc options:

`-MD'
Generate makefile fragment with dependencies.

`-MF depfile'
Use `depfile' as output for -MD.

Note: GCC options `-Ox', `-fx' and `-mx' are ignored.

3. C language support

3.1 ANSI C

TCC implements all the ANSI C standard, including structure bit fields and floating point numbers (long double, double, and float fully supported).

3.2 ISOC99 extensions

TCC implements many features of the new C standard: ISO C99. Currently missing items are: complex and imaginary numbers and variable length arrays.

Currently implemented ISOC99 features:

  • 64 bit long long types are fully supported.

  • The boolean type _Bool is supported.

  • __func__ is a string variable containing the current function name.

  • Variadic macros: __VA_ARGS__ can be used for function-like macros:
        #define dprintf(level, __VA_ARGS__) printf(__VA_ARGS__)

    dprintf can then be used with a variable number of parameters.

  • Declarations can appear anywhere in a block (as in C++).

  • Array and struct/union elements can be initialized in any order by using designators:
        struct { int x, y; } st[10] = { [0].x = 1, [0].y = 2 };

    int tab[10] = { 1, 2, [5] = 5, [9] = 9};
  • Compound initializers are supported:
        int *p = (int []){ 1, 2, 3 };
    to initialize a pointer pointing to an initialized array. The same works for structures and strings.

  • Hexadecimal floating point constants are supported:
              double d = 0x1234p10;

    is the same as writing
              double d = 4771840.0;

  • inline keyword is ignored.

  • restrict keyword is ignored.

3.3 GNU C extensions

TCC implements some GNU C extensions:

  • array designators can be used without '=':
        int a[10] = { [0] 1, [5] 2, 3, 4 };

  • Structure field designators can be a label:
        struct { int x, y; } st = { x: 1, y: 1};
    instead of
        struct { int x, y; } st = { .x = 1, .y = 1};

  • \e is ASCII character 27.

  • case ranges : ranges can be used in cases:
        switch(a) {
    case 1 ... 9:
          printf("range 1 to 9\n");
          break;
    default:
          printf("unexpected\n");
          break;
    }

  • The keyword __attribute__ is handled to specify variable or function attributes. The following attributes are supported:
    • aligned(n): align a variable or a structure field to n bytes (must be a power of two).

    • packed: force alignment of a variable or a structure field to 1.

    • section(name): generate function or data in assembly section name (name is a string containing the section name) instead of the default section.

    • unused: specify that the variable or the function is unused.

    • cdecl: use standard C calling convention (default).

    • stdcall: use Pascal-like calling convention.

    • regparm(n): use fast i386 calling convention. n must be between 1 and 3. The first n function parameters are respectively put in registers %eax, %edx and %ecx.

    • dllexport: export function from dll/executable (win32 only)

    Here are some examples:
        int a __attribute__ ((aligned(8), section(".mysection")));

    align variable a to 8 bytes and put it in section .mysection.

        int my_add(int a, int b) __attribute__ ((section(".mycodesection")))
    {
        return a + b;
    }

    generate function my_add in section .mycodesection.

  • GNU style variadic macros:
        #define dprintf(fmt, args...) printf(fmt, ## args)

    dprintf("no arg\n");
    dprintf("one arg %d\n", 1);

  • __FUNCTION__ is interpreted as C99 __func__ (so it has not exactly the same semantics as string literal GNUC where it is a string literal).

  • The __alignof__ keyword can be used as sizeof to get the alignment of a type or an expression.

  • The typeof(x) returns the type of x. x is an expression or a type.

  • Computed gotos: &&label returns a pointer of type void * on the goto label label. goto *expr can be used to jump on the pointer resulting from expr.

  • Inline assembly with asm instruction:
    static inline void * my_memcpy(void * to, const void * from, size_t n)
{
int d0, d1, d2;
__asm__ __volatile__(
        "rep ; movsl\n\t"
        "testb $2,%b4\n\t"
        "je 1f\n\t"
        "movsw\n"
        "1:\ttestb $1,%b4\n\t"
        "je 2f\n\t"
        "movsb\n"
        "2:"
        : "=&c" (d0), "=&D" (d1), "=&S" (d2)
        :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
        : "memory");
return (to);
}

    TCC includes its own x86 inline assembler with a gas-like (GNU assembler) syntax. No intermediate files are generated. GCC 3.x named operands are supported.

  • __builtin_types_compatible_p() and __builtin_constant_p() are supported.

  • #pragma pack is supported for win32 compatibility.

3.4 TinyCC extensions

  • __TINYC__ is a predefined macro to 1 to indicate that you use TCC.

  • #! at the start of a line is ignored to allow scripting.

  • Binary digits can be entered (0b101 instead of 5).

  • __BOUNDS_CHECKING_ON is defined if bound checking is activated.

4. TinyCC Assembler

Since version 0.9.16, TinyCC integrates its own assembler. TinyCC assembler supports a gas-like syntax (GNU assembler). You can desactivate assembler support if you want a smaller TinyCC executable (the C compiler does not rely on the assembler).

TinyCC Assembler is used to handle files with `.S' (C preprocessed assembler) and `.s' extensions. It is also used to handle the GNU inline assembler with the asm keyword.

4.1 Syntax

TinyCC Assembler supports most of the gas syntax. The tokens are the same as C.

  • C and C++ comments are supported.

  • Identifiers are the same as C, so you cannot use '.' or '$'.

  • Only 32 bit integer numbers are supported.

4.2 Expressions

  • Integers in decimal, octal and hexa are supported.

  • Unary operators: +, -, ~.

  • Binary operators in decreasing priority order:

    1. *, /, %
    2. &, |, ^
    3. +, -

  • A value is either an absolute number or a label plus an offset. All operators accept absolute values except '+' and '-'. '+' or '-' can be used to add an offset to a label. '-' supports two labels only if they are the same or if they are both defined and in the same section.

4.3 Labels

  • All labels are considered as local, except undefined ones.

  • Numeric labels can be used as local gas-like labels. They can be defined several times in the same source. Use 'b' (backward) or 'f' (forward) as suffix to reference them:

     1:
      jmp 1b /* jump to '1' label before */
      jmp 1f /* jump to '1' label after */
 1:

4.4 Directives

All directives are preceeded by a '.'. The following directives are supported:

  • .align n[,value]
  • .skip n[,value]
  • .space n[,value]
  • .byte value1[,...]
  • .word value1[,...]
  • .short value1[,...]
  • .int value1[,...]
  • .long value1[,...]
  • .quad immediate_value1[,...]
  • .globl symbol
  • .global symbol
  • .section section
  • .text
  • .data
  • .bss
  • .fill repeat[,size[,value]]
  • .org n
  • .previous
  • .string string[,...]
  • .asciz string[,...]
  • .ascii string[,...]

4.5 X86 Assembler

All X86 opcodes are supported. Only ATT syntax is supported (source then destination operand order). If no size suffix is given, TinyCC tries to guess it from the operand sizes.

Currently, MMX opcodes are supported but not SSE ones.

5. TinyCC Linker

5.1 ELF file generation

TCC can directly output relocatable ELF files (object files), executable ELF files and dynamic ELF libraries without relying on an external linker.

Dynamic ELF libraries can be output but the C compiler does not generate position independent code (PIC). It means that the dynamic library code generated by TCC cannot be factorized among processes yet.

TCC linker eliminates unreferenced object code in libraries. A single pass is done on the object and library list, so the order in which object files and libraries are specified is important (same constraint as GNU ld). No grouping options (`--start-group' and `--end-group') are supported.

5.2 ELF file loader

TCC can load ELF object files, archives (.a files) and dynamic libraries (.so).

5.3 PE-i386 file generation

TCC for Windows supports the native Win32 executable file format (PE-i386). It generates EXE files (console and gui) and DLL files.

For usage on Windows, see also tcc-win32.txt.

5.4 GNU Linker Scripts

Because on many Linux systems some dynamic libraries (such as `/usr/lib/libc.so') are in fact GNU ld link scripts (horrible!), the TCC linker also supports a subset of GNU ld scripts.

The GROUP and FILE commands are supported. OUTPUT_FORMAT and TARGET are ignored.

Example from `/usr/lib/libc.so':
/* GNU ld script
   Use the shared library, but some functions are only in
   the static library, so try that secondarily.  */
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )

6. TinyCC Memory and Bound checks

This feature is activated with the `-b' (see section 2. Command line invocation).

Note that pointer size is unchanged and that code generated with bound checks is fully compatible with unchecked code. When a pointer comes from unchecked code, it is assumed to be valid. Even very obscure C code with casts should work correctly.

For more information about the ideas behind this method, see http://www.doc.ic.ac.uk/~phjk/BoundsChecking.html.

Here are some examples of caught errors:

Invalid range with standard string function:
{
    char tab[10];
    memset(tab, 0, 11);
}

Out of bounds-error in global or local arrays:
{
    int tab[10];
    for(i=0;i<11;i++) {
        sum += tab[i];
    }
}

Out of bounds-error in malloc'ed data:
{
    int *tab;
    tab = malloc(20 * sizeof(int));
    for(i=0;i<21;i++) {
        sum += tab4[i];
    }
    free(tab);
}

Access of freed memory:
{
    int *tab;
    tab = malloc(20 * sizeof(int));
    free(tab);
    for(i=0;i<20;i++) {
        sum += tab4[i];
    }
}

Double free:
{
    int *tab;
    tab = malloc(20 * sizeof(int));
    free(tab);
    free(tab);
}

7. The libtcc library

The libtcc library enables you to use TCC as a backend for dynamic code generation.

Read the `libtcc.h' to have an overview of the API. Read `libtcc_test.c' to have a very simple example.

The idea consists in giving a C string containing the program you want to compile directly to libtcc. Then you can access to any global symbol (function or variable) defined.

8. Developer's guide

This chapter gives some hints to understand how TCC works. You can skip it if you do not intend to modify the TCC code.

8.1 File reading

The BufferedFile structure contains the context needed to read a file, including the current line number. tcc_open() opens a new file and tcc_close() closes it. inp() returns the next character.

8.2 Lexer

next() reads the next token in the current file. next_nomacro() reads the next token without macro expansion.

tok contains the current token (see TOK_xxx) constants. Identifiers and keywords are also keywords. tokc contains additional infos about the token (for example a constant value if number or string token).

8.3 Parser

The parser is hardcoded (yacc is not necessary). It does only one pass, except:

  • For initialized arrays with unknown size, a first pass is done to count the number of elements.

  • For architectures where arguments are evaluated in reverse order, a first pass is done to reverse the argument order.

8.4 Types

The types are stored in a single 'int' variable. It was choosen in the first stages of development when tcc was much simpler. Now, it may not be the best solution.

#define VT_INT        0  /* integer type */
#define VT_BYTE       1  /* signed byte type */
#define VT_SHORT      2  /* short type */
#define VT_VOID       3  /* void type */
#define VT_PTR        4  /* pointer */
#define VT_ENUM       5  /* enum definition */
#define VT_FUNC       6  /* function type */
#define VT_STRUCT     7  /* struct/union definition */
#define VT_FLOAT      8  /* IEEE float */
#define VT_DOUBLE     9  /* IEEE double */
#define VT_LDOUBLE   10  /* IEEE long double */
#define VT_BOOL      11  /* ISOC99 boolean type */
#define VT_LLONG     12  /* 64 bit integer */
#define VT_LONG      13  /* long integer (NEVER USED as type, only
                            during parsing) */
#define VT_BTYPE      0x000f /* mask for basic type */
#define VT_UNSIGNED   0x0010  /* unsigned type */
#define VT_ARRAY      0x0020  /* array type (also has VT_PTR) */
#define VT_VLA        0x20000 /* VLA type (also has VT_PTR and VT_ARRAY) */
#define VT_BITFIELD   0x0040  /* bitfield modifier */
#define VT_CONSTANT   0x0800  /* const modifier */
#define VT_VOLATILE   0x1000  /* volatile modifier */
#define VT_SIGNED     0x2000  /* signed type */

#define VT_STRUCT_SHIFT 18   /* structure/enum name shift (14 bits left) */

When a reference to another type is needed (for pointers, functions and structures), the 32 - VT_STRUCT_SHIFT high order bits are used to store an identifier reference.

The VT_UNSIGNED flag can be set for chars, shorts, ints and long longs.

Arrays are considered as pointers VT_PTR with the flag VT_ARRAY set. Variable length arrays are considered as special arrays and have flag VT_VLA set instead of VT_ARRAY.

The VT_BITFIELD flag can be set for chars, shorts, ints and long longs. If it is set, then the bitfield position is stored from bits VT_STRUCT_SHIFT to VT_STRUCT_SHIFT + 5 and the bit field size is stored from bits VT_STRUCT_SHIFT + 6 to VT_STRUCT_SHIFT + 11.

VT_LONG is never used except during parsing.

During parsing, the storage of an object is also stored in the type integer:

#define VT_EXTERN  0x00000080  /* extern definition */
#define VT_STATIC  0x00000100  /* static variable */
#define VT_TYPEDEF 0x00000200  /* typedef definition */
#define VT_INLINE  0x00000400  /* inline definition */
#define VT_IMPORT  0x00004000  /* win32: extern data imported from dll */
#define VT_EXPORT  0x00008000  /* win32: data exported from dll */
#define VT_WEAK    0x00010000  /* win32: data exported from dll */

8.5 Symbols

All symbols are stored in hashed symbol stacks. Each symbol stack contains Sym structures.

Sym.v contains the symbol name (remember an idenfier is also a token, so a string is never necessary to store it). Sym.t gives the type of the symbol. Sym.r is usually the register in which the corresponding variable is stored. Sym.c is usually a constant associated to the symbol like its address for normal symbols, and the number of entries for symbols representing arrays. Variable length array types use Sym.c as a location on the stack which holds the runtime sizeof for the type.

Four main symbol stacks are defined:

define_stack
for the macros (#defines).

global_stack
for the global variables, functions and types.

local_stack
for the local variables, functions and types.

global_label_stack
for the local labels (for goto).

label_stack
for GCC block local labels (see the __label__ keyword).

sym_push() is used to add a new symbol in the local symbol stack. If no local symbol stack is active, it is added in the global symbol stack.

sym_pop(st,b) pops symbols from the symbol stack st until the symbol b is on the top of stack. If b is NULL, the stack is emptied.

sym_find(v) return the symbol associated to the identifier v. The local stack is searched first from top to bottom, then the global stack.

8.6 Sections

The generated code and datas are written in sections. The structure Section contains all the necessary information for a given section. new_section() creates a new section. ELF file semantics is assumed for each section.

The following sections are predefined:

text_section
is the section containing the generated code. ind contains the current position in the code section.

data_section
contains initialized data

bss_section
contains uninitialized data

bounds_section
lbounds_section
are used when bound checking is activated

stab_section
stabstr_section
are used when debugging is actived to store debug information

symtab_section
strtab_section
contain the exported symbols (currently only used for debugging).

8.7 Code generation

8.7.1 Introduction

The TCC code generator directly generates linked binary code in one pass. It is rather unusual these days (see gcc for example which generates text assembly), but it can be very fast and surprisingly little complicated.

The TCC code generator is register based. Optimization is only done at the expression level. No intermediate representation of expression is kept except the current values stored in the value stack.

On x86, three temporary registers are used. When more registers are needed, one register is spilled into a new temporary variable on the stack.

8.7.2 The value stack

When an expression is parsed, its value is pushed on the value stack (vstack). The top of the value stack is vtop. Each value stack entry is the structure SValue.

SValue.t is the type. SValue.r indicates how the value is currently stored in the generated code. It is usually a CPU register index (REG_xxx constants), but additional values and flags are defined:

#define VT_CONST     0x00f0
#define VT_LLOCAL    0x00f1
#define VT_LOCAL     0x00f2
#define VT_CMP       0x00f3
#define VT_JMP       0x00f4
#define VT_JMPI      0x00f5
#define VT_LVAL      0x0100
#define VT_SYM       0x0200
#define VT_MUSTCAST  0x0400
#define VT_MUSTBOUND 0x0800
#define VT_BOUNDED   0x8000
#define VT_LVAL_BYTE     0x1000
#define VT_LVAL_SHORT    0x2000
#define VT_LVAL_UNSIGNED 0x4000
#define VT_LVAL_TYPE     (VT_LVAL_BYTE | VT_LVAL_SHORT | VT_LVAL_UNSIGNED)

VT_CONST
indicates that the value is a constant. It is stored in the union SValue.c, depending on its type.

VT_LOCAL
indicates a local variable pointer at offset SValue.c.i in the stack.

VT_CMP
indicates that the value is actually stored in the CPU flags (i.e. the value is the consequence of a test). The value is either 0 or 1. The actual CPU flags used is indicated in SValue.c.i.

If any code is generated which destroys the CPU flags, this value MUST be put in a normal register.

VT_JMP
VT_JMPI
indicates that the value is the consequence of a conditional jump. For VT_JMP, it is 1 if the jump is taken, 0 otherwise. For VT_JMPI it is inverted.

These values are used to compile the || and && logical operators.

If any code is generated, this value MUST be put in a normal register. Otherwise, the generated code won't be executed if the jump is taken.

VT_LVAL
is a flag indicating that the value is actually an lvalue (left value of an assignment). It means that the value stored is actually a pointer to the wanted value.

Understanding the use VT_LVAL is very important if you want to understand how TCC works.

VT_LVAL_BYTE
VT_LVAL_SHORT
VT_LVAL_UNSIGNED
if the lvalue has an integer type, then these flags give its real type. The type alone is not enough in case of cast optimisations.

VT_LLOCAL
is a saved lvalue on the stack. VT_LLOCAL should be eliminated ASAP because its semantics are rather complicated.

VT_MUSTCAST
indicates that a cast to the value type must be performed if the value is used (lazy casting).

VT_SYM
indicates that the symbol SValue.sym must be added to the constant.

VT_MUSTBOUND
VT_BOUNDED
are only used for optional bound checking.

8.7.3 Manipulating the value stack

vsetc() and vset() pushes a new value on the value stack. If the previous vtop was stored in a very unsafe place(for example in the CPU flags), then some code is generated to put the previous vtop in a safe storage.

vpop() pops vtop. In some cases, it also generates cleanup code (for example if stacked floating point registers are used as on x86).

The gv(rc) function generates code to evaluate vtop (the top value of the stack) into registers. rc selects in which register class the value should be put. gv() is the most important function of the code generator.

gv2() is the same as gv() but for the top two stack entries.

8.7.4 CPU dependent code generation

See the `i386-gen.c' file to have an example.

load()
must generate the code needed to load a stack value into a register.

store()
must generate the code needed to store a register into a stack value lvalue.

gfunc_start()
gfunc_param()
gfunc_call()
should generate a function call

gfunc_prolog()
gfunc_epilog()
should generate a function prolog/epilog.

gen_opi(op)
must generate the binary integer operation op on the two top entries of the stack which are guaranted to contain integer types.

The result value should be put on the stack.

gen_opf(op)
same as gen_opi() for floating point operations. The two top entries of the stack are guaranted to contain floating point values of same types.

gen_cvt_itof()
integer to floating point conversion.

gen_cvt_ftoi()
floating point to integer conversion.

gen_cvt_ftof()
floating point to floating point of different size conversion.

gen_bounded_ptr_add()
gen_bounded_ptr_deref()
are only used for bounds checking.

8.8 Optimizations done

Constant propagation is done for all operations. Multiplications and divisions are optimized to shifts when appropriate. Comparison operators are optimized by maintaining a special cache for the processor flags. &&, || and ! are optimized by maintaining a special 'jump target' value. No other jump optimization is currently performed because it would require to store the code in a more abstract fashion.

Concept Index

Jump to: _
A B C D E F G I J L M O P Q R S T U V W

 | Index Entry | Section
_ |  |
 | __asm__ | 3.3 GNU C extensions
A |  |
 | align directive | 4.4 Directives
 | aligned attribute | 3.3 GNU C extensions
 | ascii directive | 4.4 Directives
 | asciz directive | 4.4 Directives
 | assembler | 4.5 X86 Assembler
 | assembler directives | 4.4 Directives
 | assembly, inline | 3.3 GNU C extensions
B |  |
 | bound checks | 6. TinyCC Memory and Bound checks
 | bss directive | 4.4 Directives
 | byte directive | 4.4 Directives
C |  |
 | caching processor flags | 8.8 Optimizations done
 | cdecl attribute | 3.3 GNU C extensions
 | code generation | 8.7 Code generation
 | comparison operators | 8.8 Optimizations done
 | constant propagation | 8.8 Optimizations done
 | CPU dependent | 8.7.4 CPU dependent code generation
D |  |
 | data directive | 4.4 Directives
 | directives, assembler | 4.4 Directives
 | dllexport attribute | 3.3 GNU C extensions
E |  |
 | ELF | 5.1 ELF file generation
F |  |
 | FILE, linker command | 5.4 GNU Linker Scripts
 | fill directive | 4.4 Directives
 | flags, caching | 8.8 Optimizations done
G |  |
 | gas | 3.3 GNU C extensions
 | global directive | 4.4 Directives
 | globl directive | 4.4 Directives
 | GROUP, linker command | 5.4 GNU Linker Scripts
I |  |
 | inline assembly | 3.3 GNU C extensions
 | int directive | 4.4 Directives
J |  |
 | jump optimization | 8.8 Optimizations done
L |  |
 | linker | 5. TinyCC Linker
 | linker scripts | 5.4 GNU Linker Scripts
 | long directive | 4.4 Directives
M |  |
 | memory checks | 6. TinyCC Memory and Bound checks
O |  |
 | optimizations | 8.8 Optimizations done
 | org directive | 4.4 Directives
 | OUTPUT_FORMAT, linker command | 5.4 GNU Linker Scripts
P |  |
 | packed attribute | 3.3 GNU C extensions
 | PE-i386 | 5.3 PE-i386 file generation
 | previous directive | 4.4 Directives
Q |  |
 | quad directive | 4.4 Directives
R |  |
 | regparm attribute | 3.3 GNU C extensions
S |  |
 | scripts, linker | 5.4 GNU Linker Scripts
 | section attribute | 3.3 GNU C extensions
 | section directive | 4.4 Directives
 | short directive | 4.4 Directives
 | skip directive | 4.4 Directives
 | space directive | 4.4 Directives
 | stdcall attribute | 3.3 GNU C extensions
 | strength reduction | 8.8 Optimizations done
 | string directive | 4.4 Directives
T |  |
 | TARGET, linker command | 5.4 GNU Linker Scripts
 | text directive | 4.4 Directives
U |  |
 | unused attribute | 3.3 GNU C extensions
V |  |
 | value stack | 8.7.3 Manipulating the value stack
 | value stack, introduction | 8.7.2 The value stack
W |  |
 | word directive | 4.4 Directives

Jump to: _
A B C D E F G I J L M O P Q R S T U V W

Table of Contents

    1. Introduction
    2. Command line invocation
      2.1 Quick start
      2.2 Option summary
    3. C language support
      3.1 ANSI C
      3.2 ISOC99 extensions
      3.3 GNU C extensions
      3.4 TinyCC extensions
    4. TinyCC Assembler
      4.1 Syntax
      4.2 Expressions
      4.3 Labels
      4.4 Directives
      4.5 X86 Assembler
    5. TinyCC Linker
      5.1 ELF file generation
      5.2 ELF file loader
      5.3 PE-i386 file generation
      5.4 GNU Linker Scripts
    6. TinyCC Memory and Bound checks
    7. The libtcc library
    8. Developer's guide
      8.1 File reading
      8.2 Lexer
      8.3 Parser
      8.4 Types
      8.5 Symbols
      8.6 Sections
      8.7 Code generation
        8.7.1 Introduction
        8.7.2 The value stack
        8.7.3 Manipulating the value stack
        8.7.4 CPU dependent code generation
      8.8 Optimizations done
    Concept Index

Short Table of Contents

1. Introduction
2. Command line invocation
3. C language support
4. TinyCC Assembler
5. TinyCC Linker
6. TinyCC Memory and Bound checks
7. The libtcc library
8. Developer's guide
Concept Index

About this document

This document was generated on February, 15 2013 using texi2html

The buttons in the navigation panels have the following meaning:

Button | Name | Go to | From 1.2.3 go to
[ < ] | Back | previous section in reading order | 1.2.2
[ > ] | Forward | next section in reading order | 1.2.4
[ << ] | FastBack | previous or up-and-previous section | 1.1
[ Up ] | Up | up section | 1.2
[ >> ] | FastForward | next or up-and-next section | 1.3
[Top] | Top | cover (top) of document |
[Contents] | Contents | table of contents |
[Index] | Index | concept index |
[ ? ] | About | this page |

where the Example assumes that the current position is at Subsubsection One-Two-Three of a document of the following structure:
  • 1. Section One
    • 1.1 Subsection One-One
      • ...
    • 1.2 Subsection One-Two
      • 1.2.1 Subsubsection One-Two-One
      • 1.2.2 Subsubsection One-Two-Two
      • 1.2.3 Subsubsection One-Two-Three <== Current Position
      • 1.2.4 Subsubsection One-Two-Four
    • 1.3 Subsection One-Three
      • ...
    • 1.4 Subsection One-Four

This document was generated on February, 15 2013 using texi2html


ASM Mode Reel

    TinyCC
    ======

    This file contains specific information for usage of TinyCC
    under MS-Windows.  See tcc-doc.html to have all the features.

    Installation from the binary ZIP package:
    -----------------------------------------
    Unzip the package to a directory of your choice.

    Set the system PATH:
    --------------------
    To be able to invoke the compiler from everywhere on your computer by
    just typing "tcc", please add the directory containing tcc.exe to your
    system PATH.

    Examples:
    ---------
    Open a console window (DOS box) and 'cd' to the examples directory.

    For the 'Fibonacci' example type:

    tcc fib.c

    For the 'Hello Windows' GUI example type:

    tcc hello_win.c

    For the 'Hello DLL' example type

    tcc -shared dll.c
    tiny_impdef dll.dll (optional)
        tcc hello_dll.c dll.def

    Using libtcc as JIT compiler in your program
    --------------------------------------------
    Check out the 'libtcc_test' example:

    - Running it from source:
        tcc -I libtcc libtcc/libtcc.def -run examples/libtcc_test.c

    - Compiling with TCC:
        tcc examples/libtcc_test.c -I libtcc libtcc/libtcc.def

    - Compiling with MinGW:
        gcc examples/libtcc_test.c -I libtcc libtcc.dll

    - Compiling with MSVC:
        lib /def:libtcc\libtcc.def /out:libtcc.lib
        cl /MD examples/libtcc_test.c -I libtcc libtcc.lib

    Import Definition Files:
    ------------------------
    To link with Windows system DLLs, TCC uses import definition
    files (.def) instead of libraries.

    The included 'tiny_impdef' program may be used to make additional
    .def files for any DLL. For example:

        tiny_impdef.exe opengl32.dll

    Put opengl32.def into the tcc/lib directory.  Specify -lopengl32 at
    the TCC commandline to link a program that uses opengl32.dll.

    Header Files:
    -------------
    The system header files (except _mingw.h) are from the MinGW
    distribution:

    http://www.mingw.org/

    From the windows headers, only a minimal set is included.  If you need
    more,  get MinGW's "w32api" package.  Extract the files from "include"
    into your "tcc/include/winapi" directory.

    Resource Files:
    ---------------
    TCC can link windows resources in coff format as generated by MinGW's
    windres.exe.  For example:

        windres -O coff app.rc -o appres.o
        tcc app.c appres.o -o app.exe

    Tiny Libmaker:
    --------------
    The included tiny_libmaker tool by Timovj Lahde can be used as
    'ar' replacement to make a library from several object files:

    tiny_libmaker [rcs] library objectfiles ...

    Compilation from source:
    ------------------------
    * You can use the MinGW and MSYS tools available at

        http://www.mingw.org

      Untar the TCC archive and type in the MSYS shell:

        ./configure [--prefix installpath]
        make
        make install

    The default install location is c:\Program Files\tcc

    * Alternatively you can compile TCC with just GCC from MinGW using

        build-tcc.bat (from the win32 directory)

      To install, copy the entire contents of the win32 directory to
      where you want.

    Limitations:
    ------------
    - On the object file level, currently TCC supports only the ELF format,
      not COFF as used by MinGW and MSVC.  It is not possible to exchange
      object files or libraries between TCC and these compilers.  However
      libraries for TCC from objects by TCC can be made using tiny_libmaker
      or MinGW's ar.

    - No leading underscore is generated in the ELF symbols.

    - Bounds checking (option -b) is not supported on 64-bit OS.

    Documentation and License:
    --------------------------
    TCC is distributed under the GNU Lesser General Public License. (See
    COPYING file or http://www.gnu.org/licenses/lgpl-2.1.html)

    TinyCC homepage is at:

    http://fabrice.bellard.free.fr/tcc/

    WinAPI Help and 3rd-party tools:
    --------------------------------
    The Windows API documentation (Win95) in a single .hlp file is
    available on the lcc-win32 site as "win32hlp.exe" or from other
    locations as "win32hlp_big.zip".

    A nice RAD tool to create windows resources (dialog boxes etc.) is
    "ResEd", available at the RadASM website.

    --- grischka